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 <[email protected]>
* 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() { }