After merging from trunk this morning, I discovered that DECL_SIZE_UNIT is now being used to store lists of specializations. I had been using that to store template constraints. Oops.
This patch moves constraints outside the usual tree structures into an association maintained in a hash table. It also lays the framework for allowing constraints to be associated with any _*DECL node (templates, functions, variables, types, etc). Changelog below; committed as 212103. 2014-06-28 Andrew Sutton <andrew.n.sut...@gmail.com> * gcc/cp/cp-tree.h (DECL_CONSTRAINTS): Remove this macro; use get_constraints instead. (set_constraints): new. * gcc/cp/cxx-pretty-print.c (pp_cxx_template_declaration): Use get_constraints. * gcc/cp/pt.c (get_specialization_constraints): Use get_constraints. (build_template_decl): Use get_constraints. (process_partial_specialization): Use get_constraints. (add_inherited_template_parms): Use get_constraints. (redeclare_class_template): Use get_constraints. (is_compatible_template_arg): Use get_constraints. (tsubst_friend_class): Use get_constraints. (tsubst_decl): Uset get_constraints. * gcc/cp/semantics.c (finish_template_template_parm): Use get_constraints. (fixup_template_type): Use get_constraints. * gcc/cp/constraint.cc (constraints): New global association of declarations to constraints. (get_constraints): Return the associated constraints from the hash table. (set_constraints): New. Associate constraints with a declaration. (check_template_constraints): Use get_constraints. (equivalently_constrained): Use get_constraints. (more_constrained): Use get_constraints. (diagnose_constraints): Use get_constraints. * gcc/testsuite/g++.dg/concepts/partial-spec.C: New. Andrew
Index: gcc/cp/cxx-pretty-print.c =================================================================== --- gcc/cp/cxx-pretty-print.c (revision 212100) +++ gcc/cp/cxx-pretty-print.c (working copy) @@ -2220,7 +2220,7 @@ pp_cxx_template_declaration (cxx_pretty_ pp_newline_and_indent (pp, 3); } - if (tree c = DECL_CONSTRAINTS (t)) + if (tree c = get_constraints (t)) { pp_cxx_ws_string (pp, "requires"); pp->expression (CI_REQUIREMENTS (c)); Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 212101) +++ gcc/cp/pt.c (working copy) @@ -846,7 +846,7 @@ get_specialization_constraints (tree typ // that type. If it is an explicit specialization, return null since // non-templates cannot be constrained. if (tree d = get_specializing_template_decl (type)) - return DECL_CONSTRAINTS (d); + return get_constraints (d); else return NULL_TREE; } @@ -4147,10 +4147,10 @@ build_template_decl (tree decl, tree par { tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE); DECL_TEMPLATE_PARMS (tmpl) = parms; - DECL_CONSTRAINTS (tmpl) = constr; DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl); DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl); DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p; + set_constraints (tmpl, constr); return tmpl; } @@ -4319,7 +4319,7 @@ process_partial_specialization (tree dec arguments but different constraints. */ tree main_type = TREE_TYPE (maintmpl); tree main_args = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (main_type)); - tree main_constr = DECL_CONSTRAINTS (maintmpl); + tree main_constr = get_constraints (maintmpl); if (comp_template_args (inner_args, main_args) && equivalent_constraints (current_template_reqs, main_constr)) error ("partial specialization %qT does not specialize any " @@ -5229,13 +5229,13 @@ add_inherited_template_parms (tree fn, t // If the inherited constructor was constrained, then also // propagate the constraints to the new declaration by // rewriting them in terms of the local template parameters. - tree cons = DECL_CONSTRAINTS (inherited); + tree cons = get_constraints (inherited); if (cons) { ++processing_template_decl; tree reqs = instantiate_requirements (CI_REQUIREMENTS (cons), args); --processing_template_decl; - DECL_CONSTRAINTS (tmpl) = make_constraints (reqs); + set_constraints (tmpl, make_constraints (reqs)); } DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args); @@ -5354,7 +5354,7 @@ redeclare_class_template (tree type, tre } // Cannot redeclare a class template with a different set of constraints. - if (!equivalent_constraints (DECL_CONSTRAINTS (tmpl), cons)) + if (!equivalent_constraints (get_constraints (tmpl), cons)) { error_at (input_location, "redeclaration %q#D with different " "constraints", tmpl); @@ -6586,8 +6586,8 @@ is_compatible_template_arg (tree parm, t return true; } - tree parmcons = DECL_CONSTRAINTS (parm); - tree argcons = DECL_CONSTRAINTS (arg); + tree parmcons = get_constraints (parm); + tree argcons = get_constraints (arg); // If the template parameter is constrained, we need to rewrite its // constraints in terms of the ARG's template parameters. This ensures @@ -8997,7 +8997,7 @@ tsubst_friend_class (tree friend_tmpl, t saved_input_location = input_location; input_location = DECL_SOURCE_LOCATION (friend_tmpl); - tree cons = DECL_CONSTRAINTS (tmpl); + tree cons = get_constraints (tmpl); redeclare_class_template (TREE_TYPE (tmpl), parms, cons); input_location = saved_input_location; @@ -10800,10 +10800,10 @@ tsubst_decl (tree t, tree args, tsubst_f // If constrained, also instantiate requirements. // TODO: Instantiate shorthand constraints on parameters also. // See tsubst_template_parms for that. - if (tree ci = DECL_CONSTRAINTS (t)) + if (tree ci = get_constraints (t)) { tree reqs = instantiate_requirements (CI_SPELLING (ci), args); - DECL_CONSTRAINTS (r) = finish_template_requirements (reqs); + set_constraints (r, make_constraints (reqs)); } if (PRIMARY_TEMPLATE_P (t)) Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 212101) +++ gcc/cp/semantics.c (working copy) @@ -2693,9 +2693,9 @@ finish_template_template_parm (tree aggr tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE); DECL_TEMPLATE_PARMS (tmpl) = current_template_parms; - DECL_CONSTRAINTS (tmpl) = current_template_reqs; DECL_TEMPLATE_RESULT (tmpl) = decl; DECL_ARTIFICIAL (decl) = 1; + set_constraints (tmpl, current_template_reqs); end_template_decl (); @@ -3012,7 +3012,7 @@ fixup_template_type (tree type) tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); while (specs) { - tree spec_constr = DECL_CONSTRAINTS (TREE_VALUE (specs)); + tree spec_constr = get_constraints (TREE_VALUE (specs)); // If the type and constraints match a specialization, then we // are entering that type. Note that the type comparison is Index: gcc/cp/constraint.cc =================================================================== --- gcc/cp/constraint.cc (revision 212100) +++ gcc/cp/constraint.cc (working copy) @@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. #include "vec.h" #include "target.h" #include "bitmap.h" - +#include "hash-map.h" // -------------------------------------------------------------------------- // // Requirement Construction @@ -564,22 +564,39 @@ make_constraints (tree reqs) return (tree)cinfo; } +typedef hash_map<tree, tree> constraint_map; + +// Constraints (constraint_info nodes) are associatd with declrations +// via this mapping. Note that we don't store constraints directly in trees +// so we don't use the extra memory when concepts are not enabled. This also +// provides the ability to associate constraint information with a broader +// set of declarations (i.e., templates, functions, variables, template +// parameters, etc). +static constraint_map constraints; + // Returns the template constraints of declaration T. If T is not a // template, this return NULL_TREE. Note that T must be non-null. tree get_constraints (tree t) { gcc_assert (DECL_P (t)); - if (TREE_CODE (t) != TEMPLATE_DECL) - { - if (!DECL_TEMPLATE_INFO (t)) - return NULL_TREE; - else - return DECL_CONSTRAINTS (DECL_TI_TEMPLATE (t)); - } - return DECL_CONSTRAINTS (t); + if (tree* r = constraints.get(t)) + return *r; + else + return NULL_TREE; } +// Associate the given constraint information with the declaration. +// Once set, constraints cannot be overwritten. +void +set_constraints (tree t, tree ci) +{ + gcc_assert (DECL_P (t)); + gcc_assert(!get_constraints(t)); + constraints.put(t, ci); +} + + // Returns a conjunction of shorthand requirements for the template // parameter list PARMS. Note that the requirements are stored in // the TYPE of each tree node. @@ -1187,7 +1204,7 @@ check_constraints (tree cinfo, tree args bool check_template_constraints (tree t, tree args) { - return check_constraints (DECL_CONSTRAINTS (t), args); + return check_constraints (get_constraints (t), args); } // -------------------------------------------------------------------------- // @@ -1212,7 +1229,7 @@ bool equivalently_constrained (tree a, tree b) { gcc_assert (TREE_CODE (a) == TREE_CODE (b)); - return equivalent_constraints (DECL_CONSTRAINTS (a), DECL_CONSTRAINTS (b)); + return equivalent_constraints (get_constraints (a), get_constraints (b)); } // Returns true when the A contains more atomic properties than B. @@ -1228,7 +1245,7 @@ bool more_constrained (tree a, tree b) { gcc_assert (TREE_CODE (a) == TREE_CODE (b)); - return more_constraints (DECL_CONSTRAINTS (a), DECL_CONSTRAINTS (b)); + return more_constraints (get_constraints (a), get_constraints (b)); } @@ -1535,7 +1552,7 @@ diagnose_constraints (location_t loc, tr // Diagnose the constraints by recursively decomposing and // evaluating the template requirements. - tree reqs = CI_SPELLING (DECL_CONSTRAINTS (tmpl)); + tree reqs = CI_SPELLING (get_constraints (tmpl)); diagnose_requirements (loc, reqs, args); } Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 212101) +++ gcc/cp/cp-tree.h (working copy) @@ -828,16 +828,6 @@ check_constraint_info (tree t) #define CI_ASSUMPTIONS(NODE) \ check_nonnull (check_constraint_info (NODE))->assumptions -// Access constraints for the declaration, NODE. -// -// For TEMPLATE_DECL nodes, the constraints are stored in the -// DECL_SIZE_UNIT node. -// -// TODO: This will need to be updated for shorthand constraints and -// constrained auto declarations. -#define DECL_CONSTRAINTS(NODE) \ - (DECL_SIZE_UNIT (TEMPLATE_DECL_CHECK (NODE))) - // Access the logical constraints on the template parameters introduced // at a given template parameter list level indicated by NODE. #define TEMPLATE_PARMS_CONSTRAINTS(NODE) \ @@ -6358,6 +6348,7 @@ extern tree conjoin_requirements extern tree reduce_requirements (tree); extern tree make_constraints (tree); extern tree get_constraints (tree); +extern void set_constraints (tree, tree); extern tree get_shorthand_requirements (tree); extern tree build_concept_check (tree, tree, tree = NULL_TREE);
Index: gcc/testsuite/g++.dg/concepts/partial-spec.C =================================================================== --- gcc/testsuite/g++.dg/concepts/partial-spec.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/partial-spec.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-options "-std=c++1z" } + +// Check that constraints don't break unconstrained partial +// specializations. + +template<typename T> + struct S { }; + +template<typename T> + struct S<T*> { }; + +template<> + struct S<int> { }; + +int main() { }