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() { }

Reply via email to