@@ -4424,6 +4424,14 @@ build_clone (tree fn, tree name)
TREE_TYPE (clone) = TREE_TYPE (result);
return clone;
}
+ else
+ {
+ // Clone constraints
+ if (flag_concepts)
+ if (tree ci = get_constraints (fn))
+ set_constraints (clone, copy_node (ci));
+ }
+
SET_DECL_ASSEMBLER_NAME (clone, NULL_TREE);
DECL_CLONED_FUNCTION (clone) = fn;
@@ -238,7 +238,7 @@ deduce_concept_introduction (tree expr)
tree var = DECL_TEMPLATE_RESULT (decl);
tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (decl));
- parms = coerce_template_parms (parms, args, var);
+ parms = coerce_template_parms (parms, args, var);
// Check that we are returned a proper set of arguments.
if (parms == error_mark_node)
return NULL_TREE;
@@ -248,7 +248,7 @@ deduce_concept_introduction (tree expr)
{
// Resolve the constraint check and return arguments.
if (tree info = resolve_constraint_check (expr))
- return TREE_PURPOSE (info);
+ return TREE_PURPOSE (info);
return NULL_TREE;
}
else
@@ -664,7 +664,7 @@ normalize_atom (tree t)
if (!type_dependent_expression_p (t))
if (!can_convert (boolean_type_node, TREE_TYPE (t), tf_none))
{
- error ("atomic constraint %qE is not convertible to %<bool%>", t);
+ error ("predicate constraint %qE is not convertible to %<bool%>", t);
return NULL_TREE;
}
return t;
@@ -682,6 +682,10 @@ normalize_constraints (tree reqs)
tree expr = normalize_node (reqs);
--processing_template_decl;
+ // If we couldn't normalize, then these constraints are ill-formed.
+ if (!expr)
+ return error_mark_node;
+
return expr;
}
@@ -694,13 +698,23 @@ normalize_constraints (tree reqs)
// The following functions are called by the parser and substitution rules
// to create and evaluate constraint-related nodes.
-// Returns the template constraints of declaration T. Note that
-// T must be non-null.
+// A mapping from declarations to constraint information. Note that
+// both templates and their underlying declarations are mapped to the
+// same constraint information.
+static hash_map<tree, tree> decl_constraints;
+
+// Returns the template constraints of declaration T. If T is not
+// constrained, return NULL_TREE. Note that T must be non-null.
tree
get_constraints (tree t)
{
gcc_assert (DECL_P (t));
- return LANG_DECL_MIN_CHECK (t)->constraint_info;
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+ if (tree *r = decl_constraints.get (t))
+ return *r;
+ else
+ return NULL_TREE;
}
// Associate the given constraint information with the declaration. Don't
@@ -708,8 +722,67 @@ get_constraints (tree t)
void
set_constraints (tree t, tree ci)
{
+ gcc_assert (t && DECL_P (t) && TREE_CODE (t) != TEMPLATE_DECL);
+ if (!ci)
+ return;
+
+ gcc_assert (!decl_constraints.get (t));
+ gcc_assert (check_constraint_info (ci));
+ decl_constraints.put (t, ci);
+}
+
+// Remove the associated constraints of the declaration T.
+//
+// FIXME: What if T is a template? What if it's a non-template? we
+// should remove both associations.
+void
+remove_constraints (tree t)
+{
gcc_assert (DECL_P (t));
- LANG_DECL_MIN_CHECK (t)->constraint_info = ci;
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+
+ if (decl_constraints.get (t))
+ decl_constraints.remove (t);
+}
+
+// If the recently parsed TYPE declares or defines a template or template
+// specialization, get its corresponding constraints from the current
+// template parameters and bind them to TYPE's declaration.
+tree
+associate_classtype_constraints (tree type)
+{
+ if (!type || type == error_mark_node || TREE_CODE (type) != RECORD_TYPE)
+ return type;
+
+ // An explicit class template specialization has no template
+ // parameters.
+ if (!current_template_parms)
+ return type;
+
+ if (CLASSTYPE_IS_TEMPLATE (type) || CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+ {
+ tree decl = TYPE_STUB_DECL (type);
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree ci = build_constraints (reqs, NULL_TREE);
+
+ // An implicitly instantiated member template declaration already
+ // has associated constraints. If it is defined outside of its
+ // class, then we need match these constraints against those of
+ // original declaration.
+ if (tree orig_ci = get_constraints (decl))
+ {
+ if (!equivalent_constraints (ci, orig_ci))
+ {
+ // FIXME: Improve diagnostics.
+ error ("%qT does not match any declaration", type);
+ return error_mark_node;
+ }
+ return type;
+ }
+ set_constraints (decl, ci);
+ }
+ return type;
}
// Returns a conjunction of shorthand requirements for the template
@@ -737,110 +810,26 @@ build_constraint_info ()
return (tree_constraint_info *)make_node (CONSTRAINT_INFO);
}
-// Create a constraint info object, initialized with the given template
-// requirements.
-inline tree
-init_leading_constraints (tree reqs)
-{
- tree_constraint_info* ci = build_constraint_info ();
- ci->leading_reqs = reqs;
- return (tree)ci;
-}
-
-// Initialize a constraint info object, initialized with the given
-// trailing requirements.
-inline tree
-init_trailing_constraints (tree reqs)
-{
- tree_constraint_info* ci = build_constraint_info ();
- ci->trailing_reqs = reqs;
- return (tree)ci;
-}
-
-// Update the template requirements.
-inline tree
-update_leading_constraints (tree ci, tree reqs)
-{
- tree& current = CI_LEADING_REQS (ci);
- current = conjoin_constraints (current, reqs);
- return ci;
-}
-
-// Set the trailing requirements to the given expression. Note that
-// trailing requirements cannot be updated once set: no other requirements
-// can be found after parsing a trailing requires-clause.
-inline tree
-update_trailing_constraints (tree ci, tree reqs)
-{
- gcc_assert (CI_TRAILING_REQS (ci) == NULL_TREE);
- CI_TRAILING_REQS (ci) = reqs;
- return ci;
-}
-
} // namespace
-// Return a constraint-info object containing the current template
-// requirements. If constraints have already been assigned, then these
-// are appended to the current constraints.
+// Build a constraint-info object that contains the associated requirements
+// of a declaration. This also includes the declaration's template
+// requirements TR (if any) and declaration requirements DR (if any).
//
-// Note that template constraints can be updated by the appearance of
-// constrained type specifiers in a parameter list. These update the
-// template requirements after the template header has been parsed.
-tree
-save_leading_constraints (tree reqs)
-{
- if (!reqs || reqs == error_mark_node)
- return NULL_TREE;
- else if (!current_template_reqs)
- return init_leading_constraints (reqs);
- else
- return update_leading_constraints (current_template_reqs, reqs);
-}
-
-// Return a constraint info object containing saved trailing requirements.
-// If there are already template requirements, these are added to the
-// existing requirements. Otherwise, a new constraint-info object
-// holding only these trailing requirements is returned.
+// If the declaration has neither template nor declaration requirements
+// this returns NULL_TREE, indicating an unconstrained declaration.
tree
-save_trailing_constraints (tree reqs)
+build_constraints (tree tr, tree dr)
{
- if (!reqs || reqs == error_mark_node)
+ if (!tr && !dr)
return NULL_TREE;
- else if (!current_template_reqs)
- return init_trailing_constraints (reqs);
- else
- return update_trailing_constraints (current_template_reqs, reqs);
-}
-
-// Finish the template requirements, by computing the associated
-// constraints (the conjunction of leading and trailing requirements),
-// and then decomposing that into sets of atomic propositions.
-tree
-finish_template_constraints (tree ci)
-{
- if (!ci || ci == error_mark_node)
- return NULL_TREE;
-
- // If these constraints have already been analyzed, don't do it
- // a second time. This happens when grokking a function decl
- // before creating its corresponding template.
- if (CI_ASSUMPTIONS (ci))
- return ci;
-
- // Build and normalize the associated constraints. If any constraints
- // are ill-formed, this is a hard error.
- tree r1 = CI_LEADING_REQS (ci);
- tree r2 = CI_TRAILING_REQS (ci);
- tree reqs = normalize_constraints (conjoin_constraints (r1, r2));
- CI_ASSOCIATED_REQS (ci) = reqs;
-
- // If normalization succeeds, decompose those expressions into sets
- // of atomic constraints. Otherwise, mark this as an error.
- if (reqs)
- CI_ASSUMPTIONS (ci) = decompose_assumptions (reqs);
- else
- CI_ASSUMPTIONS (ci) = error_mark_node;
- return ci;
+ tree_constraint_info* ci = build_constraint_info ();
+ ci->template_reqs = tr;
+ ci->declarator_reqs = dr;
+ ci->associated_constr = conjoin_constraints (tr, dr);
+ ci->normalized_constr = normalize_constraints (ci->associated_constr);
+ ci->assumptions = decompose_assumptions (ci->normalized_constr);
+ return (tree)ci;
}
// Returns true iff cinfo contains a valid constraint expression.
@@ -1223,7 +1212,7 @@ finish_shorthand_constraint (tree decl, tree constr)
}
return check;
- }
+}
// Returns and chains a new parameter for PARAMETER_LIST which will conform
// to the prototype given by SRC_PARM. The new parameter will have its
@@ -1320,6 +1309,12 @@ finish_concept_introduction (tree tmpl_decl, tree intro_list)
parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n));
parm_list = end_template_parm_list (parm_list);
+ for (int i = 0; i < TREE_VEC_LENGTH (parm_list); ++i)
+ if (TREE_VALUE (TREE_VEC_ELT (parm_list, i)) == error_mark_node)
+ {
+ end_template_decl ();
+ return error_mark_node;
+ }
// Build a concept check for our constraint.
tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms));
@@ -1331,6 +1326,7 @@ finish_concept_introduction (tree tmpl_decl, tree intro_list)
tree parm = TREE_VEC_ELT (parm_list, n);
TREE_VEC_ELT (check_args, n) = template_parm_to_arg (parm);
}
+
// If the template expects more parameters we should be able to use the
// defaults from our deduced form.
for (; n < TREE_VEC_LENGTH (parms); ++n)
@@ -1338,8 +1334,7 @@ finish_concept_introduction (tree tmpl_decl, tree intro_list)
// Associate the constraint.
tree reqs = build_concept_check (tmpl_decl, NULL_TREE, check_args);
- current_template_reqs = save_leading_constraints (reqs);
- TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = current_template_reqs;
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
return parm_list;
}
@@ -1525,32 +1520,20 @@ tsubst_constraint_expr (tree reqs, tree args, bool do_not_fold)
tree
tsubst_constraint_info (tree ci, tree args)
{
- if (!ci || ci == error_mark_node)
+ if (!ci || ci == error_mark_node || !check_constraint_info (ci))
return NULL_TREE;
- // Substitute into the various constraint fields.
- tree_constraint_info* result = build_constraint_info ();
- if (tree r = CI_LEADING_REQS (ci))
- result->leading_reqs = tsubst_constraint_expr (r, args, true);
- if (tree r = CI_TRAILING_REQS (ci))
- result->trailing_reqs = tsubst_constraint_expr (r, args, true);
- if (tree r = CI_ASSOCIATED_REQS (ci))
- result->associated_reqs = tsubst_constraint_expr (r, args, true);
-
- // Re-normalize the constraints to ensure that we haven't picked
- // any fatal errors when substituting.
- if (!normalize_constraints (result->associated_reqs))
- {
- result->associated_reqs = error_mark_node;
- result->assumptions = error_mark_node;
- }
- else
- {
- // Analyze the resulting constraints.
- result->assumptions = decompose_assumptions (result->associated_reqs);
- }
+ tree tr = NULL_TREE;
+ if (tree r = CI_TEMPLATE_REQS (ci))
+ tr = tsubst_constraint_expr (r, args, true);
+
+ tree dr = NULL_TREE;
+ if (tree r = CI_DECLARATOR_REQS (ci))
+ dr = tsubst_constraint_expr (r, args, true);
- return (tree)result;
+ // TODO: This is re-normalizing and re-decomposing. We probably
+ // don't need to do this.
+ return build_constraints (tr, dr);
}
// -------------------------------------------------------------------------- //
@@ -1601,7 +1584,7 @@ check_constraints (tree cinfo)
// all remaining expressions that are not constant expressions
// (e.g., template-id expressions).
else
- return check_satisfied (CI_ASSOCIATED_REQS (cinfo), NULL_TREE);
+ return check_satisfied (CI_NORMALIZED_CONSTRAINTS (cinfo), NULL_TREE);
}
// Check the constraints in CINFO against the given ARGS, returning
@@ -1616,7 +1599,7 @@ check_constraints (tree cinfo, tree args)
else if (!valid_requirements_p (cinfo))
return false;
else {
- return check_satisfied (CI_ASSOCIATED_REQS (cinfo), args);
+ return check_satisfied (CI_NORMALIZED_CONSTRAINTS (cinfo), args);
}
}
@@ -1638,6 +1621,8 @@ check_template_constraints (tree t, tree args)
bool
equivalent_constraints (tree a, tree b)
{
+ gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO);
+ gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO);
return cp_tree_equal (a, b);
}
@@ -1645,38 +1630,51 @@ equivalent_constraints (tree a, tree b)
// constraints. This is the case when A's constraints subsume B's and
// when B's also constrain A's.
bool
-equivalently_constrained (tree a, tree b)
+equivalently_constrained (tree d1, tree d2)
{
- gcc_assert (TREE_CODE (a) == TREE_CODE (b));
- return equivalent_constraints (get_constraints (a), get_constraints (b));
+ gcc_assert (TREE_CODE (d1) == TREE_CODE (d2));
+ return equivalent_constraints (get_constraints (d1), get_constraints (d2));
}
-// Returns true when the template declaration A's constraints subsume
-// those of the template declaration B.
+// Returns true when the the constraints in A subsume those in B.
bool
subsumes_constraints (tree a, tree b)
{
- gcc_assert (TREE_CODE (a) == TREE_CODE (b));
- return subsumes (get_constraints (a), get_constraints (b));
+ gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO);
+ gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO);
+ return subsumes (a, b);
}
-// Determines which of the templates, A or B, is more constrained.
-// That is, which template's constraints subsume but are not subsumed
+// Determines which of the declarations, A or B, is more constrained.
+// That is, which declaration's constraints subsume but are not subsumed
// by the other's?
//
// Returns 1 if A is more constrained than B, -1 if B is more constrained
// than A, and 0 otherwise.
int
-more_constrained (tree a, tree b)
+more_constrained (tree d1, tree d2)
{
+ tree c1 = get_constraints (d1);
+ tree c2 = get_constraints (d2);
int winner = 0;
- if (subsumes_constraints (a, b))
+ if (subsumes_constraints (c1, c2))
++winner;
- if (subsumes_constraints (b, a))
+ if (subsumes_constraints (c2, c1))
--winner;
return winner;
}
+// Returns true if d1 is at least as constrained as d2. That is, the
+// associated constraints of d1 subsume those of d2, or both declarations
+// are unconstrained.
+bool
+at_least_as_constrained (tree d1, tree d2)
+{
+ tree c1 = get_constraints (d1);
+ tree c2 = get_constraints (d2);
+ return subsumes_constraints (c1, c2);
+}
+
// -------------------------------------------------------------------------- //
// Constraint Diagnostics
@@ -2018,22 +2016,27 @@ diagnose_constraints (location_t loc, tree decl, tree args)
return;
}
+ // FIXME: Re-think how we recurse through the expression to emit
+ // diagnostics.
+
// If this is a specialization of a template, we want to diagnose
// the dependent constraints. Also update the template arguments.
- if (DECL_USE_TEMPLATE (decl))
- {
- args = DECL_TI_ARGS (decl);
- decl = DECL_TI_TEMPLATE (decl);
- }
+ // if (DECL_USE_TEMPLATE (decl))
+ // {
+ // args = DECL_TI_ARGS (decl);
+ // decl = DECL_TI_TEMPLATE (decl);
+ // }
- // Otherwise, diagnose the actual failed constraints.
- if (TREE_CODE (decl) == TEMPLATE_DECL)
- inform (loc, " constraints not satisfied %S", make_subst (decl, args));
- else
- inform (loc, " constraints not satisfied");
+ // // Otherwise, diagnose the actual failed constraints.
+ // if (TREE_CODE (decl) == TEMPLATE_DECL)
+ // inform (loc, " constraints not satisfied %S", make_subst (decl, args));
+ // else
+ // inform (loc, " constraints not satisfied");
+
+ inform (loc, " constraints not satisfied");
// Diagnose the constraints by recursively decomposing and
// evaluating the template requirements.
- tree reqs = CI_ASSOCIATED_REQS (get_constraints (decl));
+ tree reqs = CI_ASSOCIATED_CONSTRAINTS (get_constraints (decl));
diagnose_requirements (loc, reqs, args);
}
@@ -825,26 +825,23 @@ struct GTY(()) tree_template_info {
// Constraint information for a C++ declaration. Constraint information is
// comprised of:
//
-// - leading requirements (possibly null), which are introduced by the
-// template header and constrained-type-specifiers in a parameter
-// declaration clause
-// - trailing requirements (possibly null), which are introduced by the
-// a requires-clause following a declarator in a function declaration,
-// member declaration, or function definition.
-// - associated requirements (should never be null), which is the conjunction
-// of leading and trailing requirements (in that order), and
-// - assumptions which is the result of analyzed and decomposed template
-// requirements.
+// - a constraint expression introduced by the template header
+// - a constraint expression introduced by a function declarator
+// - the associated constraints, which are the conjunction of those,
+// and used for declaration matching
+// - the cached normalized associated constraints which are used
+// to support satisfaction and subsumption.
+// - assumptions which is the result of decomposing the normalized
+// constraints.
//
-// The leading and trailing requirements are kept to support pretty printing
-// constrained declarations. The associated requirements are used for
-// declaration matching, and the assumptions are computed to support
-// partial ordering of constraints.
+// The template and declarator requirements are kept to support pretty
+// printing constrained declarations.
struct GTY(()) tree_constraint_info {
struct tree_base base;
- tree leading_reqs;
- tree trailing_reqs;
- tree associated_reqs;
+ tree template_reqs;
+ tree declarator_reqs;
+ tree associated_constr;
+ tree normalized_constr;
tree assumptions;
};
@@ -861,21 +858,23 @@ check_constraint_info (tree t)
// null if no constraints were introduced in the template parameter list,
// a requirements clause after the template parameter list, or constraints
// through a constrained-type-specifier.
-#define CI_LEADING_REQS(NODE) \
- check_constraint_info (check_nonnull(NODE))->leading_reqs
+#define CI_TEMPLATE_REQS(NODE) \
+ check_constraint_info (check_nonnull(NODE))->template_reqs
// Access the expression describing the trailing constraints. This is non-null
// for any implicit instantiation of a constrained declaration. For a
// templated declaration it is non-null only when a trailing requires-clause
// was specified.
-#define CI_TRAILING_REQS(NODE) \
- check_constraint_info (check_nonnull(NODE))->trailing_reqs
+#define CI_DECLARATOR_REQS(NODE) \
+ check_constraint_info (check_nonnull(NODE))->declarator_reqs
+
+// The computed associated constraint expression for a declaration.
+#define CI_ASSOCIATED_CONSTRAINTS(NODE) \
+ check_constraint_info (check_nonnull(NODE))->associated_constr
-// Access the expression describing the associated constraints of a
-// declaration. This is the conjunction of leading and trailing
-// requirements.
-#define CI_ASSOCIATED_REQS(NODE) \
- check_constraint_info (check_nonnull(NODE))->associated_reqs
+// The normalized associated constraints.
+#define CI_NORMALIZED_CONSTRAINTS(NODE) \
+ check_constraint_info (check_nonnull(NODE))->normalized_constr
// Get the set of assumptions associated with the constraint info node.
#define CI_ASSUMPTIONS(NODE) \
@@ -1141,7 +1140,6 @@ struct GTY(()) saved_scope {
vec<tree, va_gc> *lang_base;
tree lang_name;
tree template_parms;
- tree template_reqs;
cp_binding_level *x_previous_class_level;
tree x_saved_tree;
@@ -1208,11 +1206,6 @@ struct GTY(()) saved_scope {
#define current_template_parms scope_chain->template_parms
-// When parsing a template declaration this node represents the
-// active template requirements. This includes the lists of
-// actual assumptions in the current scope.
-#define current_template_reqs scope_chain->template_reqs
-
#define processing_template_decl scope_chain->x_processing_template_decl
#define processing_specialization scope_chain->x_processing_specialization
#define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
@@ -2104,10 +2097,6 @@ struct GTY(()) lang_decl_min {
DECL_TEMPLATE_INFO. */
tree template_info;
- // The constraint info maintains information about constraints
- // associated with the declaration.
- tree constraint_info;
-
union lang_decl_u2 {
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
THUNK_VIRTUAL_OFFSET.
@@ -5152,6 +5141,8 @@ struct cp_declarator {
tree exception_specification;
/* The late-specified return type, if any. */
tree late_return_type;
+ /* The trailing requires-clause, if any. */
+ tree requires_clause;
} function;
/* For arrays. */
struct {
@@ -6473,6 +6464,9 @@ extern tree conjoin_constraints (tree, tree);
extern tree conjoin_constraints (tree);
extern tree get_constraints (tree);
extern void set_constraints (tree, tree);
+extern void remove_constraints (tree);
+extern tree associate_classtype_constraints (tree);
+extern tree build_constraints (tree, tree);
extern tree get_shorthand_constraints (tree);
extern tree build_concept_check (tree, tree, tree = NULL_TREE);
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "intl.h"
#include "cp-tree.h"
+#include "print-tree.h"
#include "cxx-pretty-print.h"
#include "tree-pretty-print.h"
@@ -1615,12 +1616,28 @@ cxx_pretty_printer::direct_declarator (tree t)
/* declarator:
direct-declarator
- ptr-operator declarator */
+ ptr-operator declarator
+
+ Concepts:
+
+ declarator:
+ basic-declarator requires-clause(opt)
+
+ basic-declarator:
+ direct-declarator
+ ptr-operator declarator
+ */
void
cxx_pretty_printer::declarator (tree t)
{
direct_declarator (t);
+
+ // Print a requires clause.
+ if (flag_concepts)
+ if (tree ci = get_constraints (t))
+ if (tree reqs = CI_DECLARATOR_REQS (ci))
+ pp_cxx_requires_clause (this, reqs);
}
/* ctor-initializer:
@@ -1671,12 +1688,6 @@ pp_cxx_function_definition (cxx_pretty_printer *pp, tree t)
tree saved_scope = pp->enclosing_scope;
pp->declaration_specifiers (t);
pp->declarator (t);
-
- // Print a requires clause.
- if (flag_concepts)
- if (tree ci = get_constraints (t))
- pp_cxx_requires_clause (pp, CI_TRAILING_REQS (ci));
-
pp_needs_newline (pp) = true;
pp->enclosing_scope = DECL_CONTEXT (t);
if (DECL_SAVED_TREE (t))
@@ -2128,12 +2139,6 @@ pp_cxx_init_declarator (cxx_pretty_printer *pp, tree t)
{
pp->declarator (t);
- // If there's a trailing requires clause, print it here.
- if (flag_concepts) {
- if (tree ci = get_constraints (t))
- pp_cxx_requires_clause (pp, CI_TRAILING_REQS (ci));
- }
-
/* We don't want to output function definitions here. There are handled
elsewhere (and the syntactic form is bogus anyway). */
if (TREE_CODE (t) != FUNCTION_DECL && DECL_INITIAL (t))
@@ -2278,10 +2283,11 @@ pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t)
if (flag_concepts)
if (tree ci = get_constraints (t))
- {
- pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci));
- pp_newline_and_indent (pp, 6);
- }
+ if (tree reqs = CI_TEMPLATE_REQS (ci))
+ {
+ pp_cxx_requires_clause (pp, reqs);
+ pp_newline_and_indent (pp, 6);
+ }
if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t))
pp_cxx_function_definition (pp, t);
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
+#include "print-tree.h"
#include "tree-hasher.h"
#include "stringpool.h"
#include "stor-layout.h"
@@ -2603,6 +2604,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
snode->remove ();
}
+ // Remove the associated constraints for newdecl, if any, before
+ // explicitly reclaiming memory.
+ remove_constraints (newdecl);
+
ggc_free (newdecl);
return olddecl;
@@ -4522,6 +4527,17 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
return declared_type;
}
+// True if the type T is a class template or a class template
+// specialization (either explicit or partial).
+static inline bool
+is_class_template_or_specialization (tree t)
+{
+ if (CLASS_TYPE_P (t)
+ && (CLASSTYPE_IS_TEMPLATE (t) || CLASSTYPE_TEMPLATE_SPECIALIZATION (t)))
+ return true;
+ return false;
+}
+
/* Called when a declaration is seen that contains no names to declare.
If its type is a reference to a structure, union or enum inherited
from a containing scope, shadow that tag name for the current scope
@@ -7600,88 +7616,6 @@ declare_simd_adjust_this (tree *tp, int *walk_subtrees, void *data)
return NULL_TREE;
}
-// Returns the leading template requirements if they exist.
-static inline tree
-get_leading_constraints ()
-{
- return current_template_reqs ?
- CI_LEADING_REQS (current_template_reqs) : NULL_TREE;
-}
-
-// When defining an out-of-class template, we want to adjust the
-// current template requirements by adding any template requirements
-// declared by the innermost template parameter list. For example:
-//
-// template<typename T>
-// struct S { template<C U> void f(); };
-//
-// template<typename T>
-// template<C U>
-// void S<T>::f() { } // #2
-//
-// When grokking #2, the constraints introduced by C are not
-// in the current_template_reqs; they are attached to the innermost
-// parameter list. The adjustment makes them part of the current
-// template requirements.
-static void
-adjust_fn_constraints (tree ctype)
-{
- // When grokking a member function template, we are processing
- // template decl at a depth greater than that of the member's
- // enclosing class. That is, this case corresponds to the
- // following declarations:
- //
- // template<C T>
- // struct S {
- // template<D U> void f(U);
- // };
- //
- // template<C T> template <D U> void S<T>::f(U) { }
- //
- // In both decls, the constraint D<U> is not the current leading
- // constraint. Make it so.
- //
- // Note that for normal member functions, there are no leading
- // requirements we need to gather.
- if (ctype && processing_template_decl > template_class_depth (ctype))
- {
- if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
- {
- // TODO: When do I ever have leading requirements for a
- // member function template?
- tree reqs = CI_LEADING_REQS (ci);
- if (reqs && !get_leading_constraints ())
- current_template_reqs = save_leading_constraints (reqs);
- }
- }
-
- // Otherwise, this is just a regular function template. Like so:
- //
- // template<C T> void f();
- //
- // Note that the constraint C<T> is not the current leading requirement
- // at this point; it was stashed before the declarator was parsed.
- // Make it the leading constraint.
- else if (!ctype && current_template_parms)
- {
- if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
- {
- tree r1 = CI_LEADING_REQS (ci);
- if (current_template_reqs)
- {
- // TODO: As with above, when do I ever have leading
- // requirements that aren't part of the template
- // constraint.
- tree r2 = CI_LEADING_REQS (current_template_reqs);
- CI_LEADING_REQS (current_template_reqs) =
- conjoin_constraints (r1, r2);
- }
- else
- current_template_reqs = save_leading_constraints (r1);
- }
- }
-}
-
/* CTYPE is class type, or null if non-class.
TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
or METHOD_TYPE.
@@ -7706,6 +7640,7 @@ grokfndecl (tree ctype,
tree declarator,
tree parms,
tree orig_declarator,
+ tree decl_reqs,
int virtualp,
enum overload_flags flags,
cp_cv_quals quals,
@@ -7743,24 +7678,14 @@ grokfndecl (tree ctype,
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
- // Possibly adjust the template requirements for out-of-class
- // function definitions. This guarantees that current_template_reqs
- // will be fully completed before calling finish_template_constraints.
+ // Set the constraints on the declaration.
if (flag_concepts)
- adjust_fn_constraints (ctype);
-
- // Check and normalize the template requirements for the declared
- // function. Note that these constraints are multiply associated
- // with both the template-decl and the function-decl.
- if (current_template_reqs)
{
- current_template_reqs
- = finish_template_constraints (current_template_reqs);
- set_constraints (decl, current_template_reqs);
-
- // TODO: Disallow these until we resolve the linking issue.
- if (current_template_reqs && !current_template_parms)
- sorry("constrained regular function");
+ tree temp_reqs = NULL_TREE;
+ if (processing_template_decl > template_class_depth (ctype))
+ temp_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree ci = build_constraints (temp_reqs, decl_reqs);
+ set_constraints (decl, ci);
}
/* If we have an explicit location, use it, otherwise use whatever
@@ -7830,12 +7755,16 @@ grokfndecl (tree ctype,
// specializations. They cannot be instantiated since they
// must match a fully instantiated function, and non-dependent
// functions cannot be constrained.
- if (current_template_reqs)
- {
- error ("constraints are not allowed in declaration "
- "of friend template specialization %qD", decl);
- return NULL_TREE;
- }
+ //
+ // FIXME [concepts] This is no longer correct. We do disallow
+ // constraints on friend function template specializations.
+ //
+ // if (current_template_reqs)
+ // {
+ // error ("constraints are not allowed in declaration "
+ // "of friend template specialization %qD", decl);
+ // return NULL_TREE;
+ // }
/* A friend declaration of the form friend void f<>(). Record
the information in the TEMPLATE_ID_EXPR. */
@@ -9002,6 +8931,18 @@ check_var_type (tree identifier, tree type)
return type;
}
+// Return a trailing requires clause for a function declarator, or
+// NULL_TREE if there is no trailing requires clause or the declarator
+// is some other kind.
+static inline tree
+get_trailing_requires_clause (const cp_declarator *declarator)
+{
+ if (declarator && declarator->kind == cdk_function)
+ return declarator->u.function.requires_clause;
+ else
+ return NULL_TREE;
+}
+
/* Given declspecs and a declarator (abstract or otherwise), determine
the name and type of the object declared and construct a DECL node
for it.
@@ -9132,6 +9073,9 @@ grokdeclarator (const cp_declarator *declarator,
explicit_intN = declspecs->explicit_intN_p;
thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
+ // Get a requires-clause attached to the declarator.
+ tree reqs = get_trailing_requires_clause (declarator);
+
// Was concept_p specified? Note that ds_concept
// implies ds_constexpr!
bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept);
@@ -10960,6 +10904,7 @@ grokdeclarator (const cp_declarator *declarator,
? unqualified_id : dname,
parms,
unqualified_id,
+ reqs,
virtualp, flags, memfn_quals, rqual, raises,
friendp ? -1 : 0, friendp, publicp,
inlinep | (2 * constexpr_p) | (4 * concept_p),
@@ -11188,7 +11133,7 @@ grokdeclarator (const cp_declarator *declarator,
TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
- virtualp, flags, memfn_quals, rqual, raises,
+ reqs, virtualp, flags, memfn_quals, rqual, raises,
1, friendp,
publicp,
inlinep | (2 * constexpr_p) | (4 * concept_p),
@@ -12578,13 +12523,11 @@ xref_tag_1 (enum tag_types tag_code, tree name,
{
if (template_header_p && MAYBE_CLASS_TYPE_P (t))
{
- // It's safe to finish the current template requirements here
- // since a class doesn't have trailing requirements.
- if (current_template_reqs)
- current_template_reqs =
- finish_template_constraints (current_template_reqs);
- if (!redeclare_class_template (t, current_template_parms,
- current_template_reqs))
+ // Check that we aren't trying to overload a class with
+ // different constraints.
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree constr = build_constraints (reqs, NULL_TREE);
+ if (!redeclare_class_template (t, current_template_parms, constr))
return error_mark_node;
}
else if (!processing_template_decl
@@ -1320,9 +1320,6 @@ dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
}
pp_cxx_end_template_argument_list (pp);
- if (flag_concepts)
- if (tree ci = get_constraints (t))
- pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci));
pp_cxx_whitespace (pp);
}
@@ -1339,6 +1336,15 @@ dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
}
}
+ if (flag_concepts)
+ if (tree ci = get_constraints (t))
+ if (check_constraint_info (ci))
+ if (tree reqs = CI_TEMPLATE_REQS (ci))
+ {
+ pp_cxx_requires_clause (pp, reqs);
+ pp_cxx_whitespace (pp);
+ }
+
if (DECL_CLASS_TEMPLATE_P (t))
dump_type (pp, TREE_TYPE (t),
((flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME
@@ -1572,7 +1578,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
if (flag_concepts)
if (tree ci = get_constraints (t))
- pp_cxx_requires_clause (pp, CI_TRAILING_REQS (ci));
+ if (tree reqs = CI_DECLARATOR_REQS (ci))
+ pp_cxx_requires_clause (pp, reqs);
dump_substitution (pp, t, template_parms, template_args, flags);
}
@@ -503,7 +503,7 @@ subsumes_constraints_nonnull (tree left, tree right)
// Check that the required expression in RIGHT is subsumed by each
// subgoal in the assumptions of LEFT.
tree as = CI_ASSUMPTIONS (left);
- tree c = CI_ASSOCIATED_REQS (right);
+ tree c = CI_NORMALIZED_CONSTRAINTS (right);
for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
if (!subsumes_prop (TREE_VEC_ELT (as, i), c))
return false;
@@ -1939,6 +1939,15 @@ implicitly_declare_fn (special_function_kind kind, tree type,
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
gcc_assert (!TREE_USED (fn));
+ // If the inherited constructor was constrained, copy the
+ // constraints.
+ if (flag_concepts && inherited_ctor)
+ {
+ tree orig_ci = get_constraints (inherited_ctor);
+ tree new_ci = copy_node (orig_ci);
+ set_constraints (fn, new_ci);
+ }
+
/* Restore PROCESSING_TEMPLATE_DECL. */
processing_template_decl = saved_processing_template_decl;
@@ -9077,9 +9077,6 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->implicit_template_scope = 0;
parser->auto_is_implicit_function_template_parm_p = false;
- // Reset the current requirements also.
- tree saved_template_reqs = release (current_template_reqs);
-
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
@@ -9117,9 +9114,6 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->implicit_template_scope = implicit_template_scope;
parser->auto_is_implicit_function_template_parm_p
= auto_is_implicit_function_template_parm_p;
-
- // Restore requirements.
- current_template_reqs = saved_template_reqs;
}
pop_deferring_access_checks ();
@@ -13443,7 +13437,7 @@ cp_parser_check_constrained_type_parm (cp_parser *parser,
return true;
}
-// Finish parsing/processing a template type parameter and chekcing
+// Finish parsing/processing a template type parameter and checking
// various restrictions.
static inline tree
cp_parser_constrained_type_template_parm (cp_parser *parser,
@@ -13476,6 +13470,7 @@ cp_parser_constrained_template_template_parm (cp_parser *parser,
tree parm = finish_template_template_parm (class_type_node, id);
current_template_parms = saved_parms;
+
return parm;
}
@@ -13905,10 +13900,6 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
tree identifier;
tree default_argument;
- // Save the current requirements before parsing the
- // template parameter list.
- tree saved_template_reqs = release (current_template_reqs);
-
/* Look for the `<'. */
cp_parser_require (parser, CPP_LESS, RT_LESS);
/* Parse the template-parameter-list. */
@@ -13922,11 +13913,7 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
tree reqs = get_shorthand_constraints (current_template_parms);
if (tree r = cp_parser_requires_clause_opt (parser))
reqs = conjoin_constraints (reqs, r);
- current_template_reqs = save_leading_constraints (reqs);
-
- // Attach the constraints to the parameter list.
- TEMPLATE_PARMS_CONSTRAINTS (current_template_parms)
- = current_template_reqs;
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
/* Look for the `class' or 'typename' keywords. */
@@ -13961,9 +13948,6 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
parameter = finish_template_template_parm (class_type_node,
identifier);
- // Restore the saved constraints.
- current_template_reqs = saved_template_reqs;
-
/* If the next token is an `=', then there is a
default-argument. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
@@ -14222,6 +14206,7 @@ cp_parser_template_id (cp_parser *parser,
}
pop_to_parent_deferring_access_checks ();
+
return template_id;
}
@@ -14479,6 +14464,11 @@ cp_parser_template_argument_list (cp_parser* parser)
argument = make_pack_expansion (argument);
}
+ // If we end up with a template decl argument, check if this is actually
+ // a template template parameter and drop the outer wrapping.
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (argument))
+ argument = TREE_TYPE (argument);
+
if (n_args == alloced)
{
alloced *= 2;
@@ -17057,6 +17047,14 @@ cp_parser_alias_declaration (cp_parser* parser)
if (decl == error_mark_node)
return decl;
+ // Attach constraints to the alias declaration.
+ if (flag_concepts)
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree constr = build_constraints (reqs, NULL_TREE);
+ set_constraints (decl, constr);
+ }
+
cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0);
if (pushed_scope)
@@ -17310,51 +17308,6 @@ cp_parser_asm_definition (cp_parser* parser)
}
}
-// An RAII guard that manages the current template requirements. The
-// constructor takes a boolean value, SAVE that, when true, resets
-// the current template requirements on construction. Otherwise, no change
-// is made. When the destructor is invoked, the current template requirements
-// are reset (made null) preventing subsequent parsing routines from using
-// them.
-struct cp_manage_requirements {
- bool save;
- tree reqs;
-
- // Construct the guard. If SAVE is true, the current requirements
- // saved and reset. Otherwise, no action is taken.
- cp_manage_requirements (bool save)
- : save (save), reqs (save ? release (current_template_reqs) : NULL_TREE)
- { }
-
- ~cp_manage_requirements ()
- {
- current_template_reqs = reqs;
- }
-};
-
-// A DECLARATOR may have a trailing requires clause; it may also have
-// requirements introduced through the use of terse notation in the
-// declaration of function parameters. Returns the parsed and analyzed
-// template requirements.
-static tree
-cp_parser_trailing_requirements (cp_parser *parser, cp_declarator *decl)
-{
- if (function_declarator_p (decl))
- {
- if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
- {
- ++cp_unevaluated_operand;
- push_function_parms (decl);
- cp_lexer_consume_token (parser->lexer);
- tree reqs = cp_parser_requires_clause (parser);
- current_template_reqs = save_trailing_constraints (reqs);
- finish_scope();
- --cp_unevaluated_operand;
- }
- }
- return current_template_reqs;
-}
-
/* Declarators [gram.dcl.decl] */
/* Parse an init-declarator.
@@ -17456,23 +17409,6 @@ cp_parser_init_declarator (cp_parser* parser,
declared. */
resume_deferring_access_checks ();
- // If scope is non-null, then we're parsing a declarator with
- // a nested-name specifier. It's possible that some component of
- // that specifier is bringing template constraints with it, which
- // we need to suppress for for the time being. For example:
- //
- // template<typename T>
- // requires C<T>()
- // void S<T>::f() requires D<T>() { ... }
- //
- // At the point we parse the 2nd requires clause, the previous the
- // current constraints will have been used to resolve the enclosing
- // class S<T>. The D<T>() requirement applies only to the definition
- // of f and do not include C<T>().
- //
- // Save requirements, resetting them if the scope was established.
- cp_manage_requirements saved_requirements (true);
-
/* Parse the declarator. */
token = cp_lexer_peek_token (parser->lexer);
declarator
@@ -17526,8 +17462,6 @@ cp_parser_init_declarator (cp_parser* parser,
attributes = cp_parser_attributes_opt (parser);
// Parse an optional trailing requires clause for the parsed declarator.
- if (flag_concepts)
- cp_parser_trailing_requirements (parser, declarator);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
@@ -17866,7 +17800,7 @@ cp_parser_init_declarator (cp_parser* parser,
FRIEND_P is true iff this declarator is a friend. */
static cp_declarator *
-cp_parser_declarator (cp_parser* parser,
+cp_parser_basic_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
int* ctor_dtor_or_conv_p,
bool* parenthesized_p,
@@ -17907,7 +17841,7 @@ cp_parser_declarator (cp_parser* parser,
cp_parser_parse_tentatively (parser);
/* Parse the dependent declarator. */
- declarator = cp_parser_declarator (parser, dcl_kind,
+ declarator = cp_parser_basic_declarator (parser, dcl_kind,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
@@ -17939,6 +17873,75 @@ cp_parser_declarator (cp_parser* parser,
return declarator;
}
+
+// A declarator may have a trailing requires clause. Because the
+// requires clause is part of the declarator the function parameters
+// are visibile in that expression.
+static tree
+cp_parser_trailing_requires_clause (cp_parser *parser, cp_declarator *decl)
+{
+ tree reqs = NULL_TREE;
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ push_function_parms (decl);
+ ++cp_unevaluated_operand;
+ reqs = cp_parser_requires_clause (parser);
+ --cp_unevaluated_operand;
+ finish_scope();
+ }
+ return reqs;
+}
+
+/* Parse a declarator. See cp_parser_basic_declarator for details.
+
+ In concepts, we allow a requires-clause to be parsed at
+ after a function declarator. The program is ill-formed for
+ any other kind of declarator.
+
+ declarator:
+ basic-declarator requires-clause [opt]
+
+ basic-declarator:
+ direct-declarator
+ ptr-operator-declarator */
+
+static cp_declarator *
+cp_parser_declarator (cp_parser* parser,
+ cp_parser_declarator_kind dcl_kind,
+ int* ctor_dtor_or_conv_p,
+ bool* parenthesized_p,
+ bool member_p, bool friend_p)
+{
+ cp_declarator *declarator =
+ cp_parser_basic_declarator (parser, dcl_kind,
+ ctor_dtor_or_conv_p,
+ parenthesized_p,
+ member_p,
+ friend_p);
+ if (!declarator)
+ return declarator;
+
+ // Parse the optional trailing requires clause. Note that
+ // the requires clause is only valid for function declarators.
+ if (flag_concepts)
+ {
+ if (declarator->kind == cdk_function)
+ {
+ declarator->u.function.requires_clause
+ = cp_parser_trailing_requires_clause (parser, declarator);
+ }
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+ {
+ error ("requires clause after non-function declaration");
+ cp_parser_skip_to_end_of_statement (parser);
+ }
+ }
+ return declarator;
+}
+
+
+
/* Parse a direct-declarator or direct-abstract-declarator.
direct-declarator:
@@ -20308,6 +20311,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
/* Parse the class-head. */
type = cp_parser_class_head (parser,
&nested_name_specifier_p);
+
/* If the class-head was a semantic disaster, skip the entire body
of the class. */
if (!type)
@@ -20349,6 +20353,10 @@ cp_parser_class_specifier_1 (cp_parser* parser)
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
+ // Associate constraints with the type.
+ if (flag_concepts)
+ type = associate_classtype_constraints (type);
+
/* Start the class. */
if (nested_name_specifier_p)
{
@@ -21489,10 +21497,6 @@ cp_parser_member_declaration (cp_parser* parser)
tree asm_specification;
int ctor_dtor_or_conv_p;
- // Save off the requirements, creating a new context
- // for constraints.
- cp_manage_requirements saved_requirements (true);
-
/* Parse the declarator. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -21593,11 +21597,6 @@ cp_parser_member_declaration (cp_parser* parser)
else
initializer = NULL_TREE;
- // Save and reset the current template requirements. Handle
- // the trailing requirements, if there are any.
- if (flag_concepts)
- cp_parser_trailing_requirements (parser, declarator);
-
/* See if we are probably looking at a function
definition. We are certainly not looking at a
member-declarator. Calling `grokfield' has
@@ -21624,9 +21623,6 @@ cp_parser_member_declaration (cp_parser* parser)
if (!friend_p)
finish_member_declaration (decl);
- if (friend_p)
- check_constrained_friend (decl, current_template_reqs);
-
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is a semicolon, consume it. */
@@ -24432,8 +24428,9 @@ cp_parser_template_introduction (cp_parser* parser)
}
// Build and associate the constraint.
- if (tree p = finish_concept_introduction (tmpl_decl, introduction_list))
- return p;
+ tree parms = finish_concept_introduction (tmpl_decl, introduction_list);
+ if (parms)
+ return parms;
error_at (token->location, "no matching concept for introduction-list");
return error_mark_node;
@@ -24452,7 +24449,6 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
bool friend_p = false;
bool need_lang_pop;
cp_token *token;
- tree saved_template_reqs;
/* Look for the `template' keyword. */
token = cp_lexer_peek_token (parser->lexer);
@@ -24495,9 +24491,6 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
cannot check the decl-specifier list. */
push_deferring_access_checks (dk_deferred);
- // Save the current template requirements.
- saved_template_reqs = release (current_template_reqs);
-
/* If the next token is `>', then we have an invalid
specialization. Rather than complain about an invalid template
parameter, issue an error message here. */
@@ -24528,20 +24521,13 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
tree reqs = get_shorthand_constraints (current_template_parms);
if (tree r = cp_parser_requires_clause_opt (parser))
reqs = conjoin_constraints (reqs, r);
- current_template_reqs = save_leading_constraints (reqs);
-
- // Attach the constraints to the template parameter list.
- // This is used to pass template requirements to out-of-class
- // member definitions.
- TEMPLATE_PARMS_CONSTRAINTS (current_template_parms)
- = current_template_reqs;
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
}
else if (flag_concepts)
{
need_lang_pop = false;
checks = NULL;
- saved_template_reqs = release (current_template_reqs);
// Scope may be changed by a nested-name-specifier.
tree saved_scope = parser->scope;
@@ -24552,14 +24538,15 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
parameter_list = cp_parser_template_introduction (parser);
if (parameter_list == error_mark_node)
{
- current_template_reqs = saved_template_reqs;
pop_deferring_access_checks ();
- return;
+ cp_parser_skip_to_end_of_statement (parser);
+ return;
}
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
+
}
else
{
@@ -24615,9 +24602,6 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
/* Finish up. */
finish_template_decl (parameter_list);
- // Restore the current template requirements.
- current_template_reqs = saved_template_reqs;
-
/* Check the template arguments for a literal operator template. */
if (decl
&& DECL_DECLARES_FUNCTION_P (decl)
@@ -24663,6 +24647,7 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
decl);
}
}
+
/* Register member declarations. */
if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
finish_member_declaration (decl);
@@ -24745,7 +24730,13 @@ cp_parser_single_declaration (cp_parser* parser,
{
if (cp_parser_declares_only_class_p (parser))
{
- decl = shadow_tag (&decl_specifiers);
+ // If this is a declaration, but not a definition, associate
+ // any constraints with the type declaration. Constraints
+ // are associated with definitions in cp_parser_class_specifier.
+ if (declares_class_or_enum == 1)
+ associate_classtype_constraints (decl_specifiers.type);
+
+ decl = shadow_tag (&decl_specifiers);
/* In this case:
@@ -25112,11 +25103,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
/* Make sure that any template parameters are in scope. */
maybe_begin_member_template_processing (member_function);
- // Restore the declaration's requirements for the parsing of
- // the definition.
- tree saved_template_reqs = release (current_template_reqs);
- current_template_reqs = get_constraints (member_function);
-
/* If the body of the function has not yet been parsed, parse it
now. */
if (DECL_PENDING_INLINE_P (member_function))
@@ -25172,9 +25158,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
/* Remove any template parameters from the symbol table. */
maybe_end_member_template_processing ();
- // Restore the template requirements.
- current_template_reqs = saved_template_reqs;
-
/* Restore the queue. */
pop_unparsed_function_queues (parser);
timevar_pop (TV_PARSE_INMETH);
@@ -33802,10 +33785,6 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
/*non_type=*/false,
/*param_pack=*/false);
- // If the invented parameter was constrained, save the constraint.
- if (tree reqs = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
- current_template_reqs = save_leading_constraints (reqs);
-
// Chain the new parameter to the list of implicit parameters.
if (parser->implicit_template_parms)
parser->implicit_template_parms
@@ -33836,6 +33815,15 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
}
+ // If the new parameter was constrained, we need to add that to the
+ // constraints in the tmeplate parameter list.
+ if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ reqs = conjoin_constraints (reqs, req);
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+ }
+
current_binding_level = entry_scope;
return new_type;
@@ -889,32 +889,68 @@ maybe_new_partial_specialization (tree type)
// Note that we also get here for injected class names and
// late-parsed template definitions. We must ensure that we
// do not create new type declarations for those cases.
- if (CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
- {
- tree constr = get_specialization_constraints (type);
- if (!equivalent_constraints (current_template_reqs, constr))
- {
- tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
- tree args = CLASSTYPE_TI_ARGS (type);
-
- // Create a new type node (and corresponding type decl)
- // for the newly declared specialization.
- tree t = make_class_type (TREE_CODE (type));
- CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type);
- TYPE_FOR_JAVA (t) = TYPE_FOR_JAVA (type);
- TYPE_CANONICAL (t) = t;
- SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
- SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args));
-
- // Build the corresponding type decl.
- tree d = create_implicit_typedef (DECL_NAME (tmpl), t);
- DECL_CONTEXT (d) = TYPE_CONTEXT (t);
- DECL_SOURCE_LOCATION (d) = input_location;
+ //
+ // FIXME: This may allow multiple partial specializations to have
+ // equivalent constraints. We need to check this against all
+ // partial specializations with euqivalent type. For exmaple:
+ //
+ // template<typename T> struct S;
+ // template<typename T> struct S<T*>; // #1
+ // template<C T> struct S<T*>; // #2
+ // template<C T> struct S<T*>; // differs from #1 but not #2
+ if (flag_concepts && CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+ {
+ tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+ tree args = CLASSTYPE_TI_ARGS (type);
+
+ // If TYPE is the same as the template's type, this is clearly
+ // not a specialization. This happens when you define a member
+ // template outside of its enclosing class.
+ if (type == DECL_TEMPLATE_RESULT (tmpl))
+ return NULL_TREE;
- return t;
+ // If there are no template parameters, this cannot be a new
+ // partial template specializtion?
+ if (!current_template_parms)
+ return NULL_TREE;
+
+ // If the constraints are not the same as those of the primary
+ // then, we can probably create a new specialization.
+ tree type_reqs = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+ tree type_constr = build_constraints (type_reqs, NULL_TREE);
+ tree main_constr = get_constraints (DECL_TEMPLATE_RESULT (tmpl));
+ if (equivalent_constraints (type_constr, main_constr))
+ return NULL_TREE;
+
+ // Also, if there's a pre-existing specialization with matching
+ // constraints, then this also isn't new.
+ tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+ while (specs)
+ {
+ tree spec_tmpl = TREE_VALUE (specs);
+ tree spec_constr = get_constraints (DECL_TEMPLATE_RESULT (spec_tmpl));
+ if (equivalent_constraints (type_constr, spec_constr))
+ return NULL_TREE;
+ specs = TREE_CHAIN (specs);
}
+
+ // Create a new type node (and corresponding type decl)
+ // for the newly declared specialization.
+ tree t = make_class_type (TREE_CODE (type));
+ CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type);
+ TYPE_FOR_JAVA (t) = TYPE_FOR_JAVA (type);
+ TYPE_CANONICAL (t) = t;
+ SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args));
+
+ // Build the corresponding type decl.
+ tree d = create_implicit_typedef (DECL_NAME (tmpl), t);
+ DECL_CONTEXT (d) = TYPE_CONTEXT (t);
+ DECL_SOURCE_LOCATION (d) = input_location;
+
+ return t;
}
- return NULL;
+
+ return NULL_TREE;
}
/* The TYPE is being declared. If it is a template type, that means it
@@ -924,7 +960,6 @@ tree
maybe_process_partial_specialization (tree type)
{
tree context;
-
if (type == error_mark_node)
return error_mark_node;
@@ -2330,8 +2365,9 @@ determine_specialization (tree template_id,
else
*targs_out = TREE_PURPOSE (templates);
- // Associate the deduced constraints with the declaration.
- if (tree ci = get_constraints (TREE_VALUE (templates)))
+ // Associate the deduced constraints with the new declaration.
+ tree tmpl = TREE_VALUE (templates);
+ if (tree ci = get_constraints (DECL_TEMPLATE_RESULT (tmpl)))
set_constraints (decl, tsubst_constraint_info (ci, *targs_out));
return TREE_VALUE (templates);
@@ -3974,9 +4010,6 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
= is_parameter_pack;
-
- // Build requirements for the parameter.
- reqs = finish_shorthand_constraint (parm, constr);
}
else
{
@@ -4009,12 +4042,14 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
decl, TREE_TYPE (parm));
TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
TYPE_CANONICAL (t) = canonical_type_parameter (t);
-
- // Build requirements for the type/template parameter.
- reqs = finish_shorthand_constraint (parm, constr);
}
DECL_ARTIFICIAL (decl) = 1;
SET_DECL_TEMPLATE_PARM_P (decl);
+
+ // Build requirements for the type/template parameter. This must be done
+ // after SET_DECL_TEMPLATE_PARM_P or process_template_parm could fail.
+ reqs = finish_shorthand_constraint (parm, constr);
+
pushdecl (decl);
// Build the parameter node linking the parameter declaration, its
@@ -4265,14 +4300,13 @@ maybe_update_decl_type (tree orig_type, tree scope)
the new template is a member template. */
tree
-build_template_decl (tree decl, tree parms, tree constr, bool member_template_p)
+build_template_decl (tree decl, tree parms, bool member_template_p)
{
tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
DECL_TEMPLATE_PARMS (tmpl) = parms;
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, finish_template_constraints (constr));
return tmpl;
}
@@ -4363,7 +4397,7 @@ process_partial_specialization (tree decl)
//
// TODO: Do we need to compare the current requirements to make
// sure this isn't a redeclaration?
- if (current_template_reqs)
+ if (TEMPLATE_PARM_CONSTRAINTS (current_template_parms))
TYPE_CANONICAL (type) = type;
inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
@@ -4438,13 +4472,20 @@ process_partial_specialization (tree decl)
The argument list of the specialization shall not be identical to
the implicit argument list of the primary template.
+ FIXME: This is redundant with the requirement that a specialization
+ shall be more specialized than the primary. H
+
Note that concepts allow partial specializations with the same list of
arguments but different constraints. */
tree main_args
= TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl)));
+
+ tree temp_reqs = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+ // FIXME: Why can't I get tmpl_constr from decl.
+ tree tmpl_constr = build_constraints (temp_reqs, NULL_TREE);
tree main_constr = get_constraints (maintmpl);
if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))
- && equivalent_constraints (current_template_reqs, main_constr))
+ && equivalent_constraints (tmpl_constr, main_constr))
error ("partial specialization %qT does not specialize any "
"template arguments", type);
@@ -4460,6 +4501,16 @@ process_partial_specialization (tree decl)
return decl;
}
+ // All things not being equal, we still need to check that the
+ // constraints are more specialized than those of the primary.
+ if (flag_concepts && !subsumes_constraints (tmpl_constr, main_constr))
+ {
+ error ("partial specialization is not more specialized than the "
+ "primary template because it is not more constrained");
+ inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here");
+ return error_mark_node;
+ }
+
/* [temp.class.spec]
A partially specialized non-type argument expression shall not
@@ -4592,7 +4643,6 @@ process_partial_specialization (tree decl)
// Build the template decl.
tree tmpl = build_template_decl (decl,
current_template_parms,
- current_template_reqs,
DECL_MEMBER_TEMPLATE_P (maintmpl));
TREE_TYPE (tmpl) = type;
DECL_TEMPLATE_RESULT (tmpl) = decl;
@@ -5149,9 +5199,11 @@ push_template_decl_real (tree decl, bool is_friend)
/* Since a template declaration already existed for this
class-type, we must be redeclaring it here. Make sure
that the redeclaration is valid. */
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree constr = build_constraints (reqs, NULL_TREE);
redeclare_class_template (TREE_TYPE (decl),
current_template_parms,
- current_template_reqs);
+ constr);
/* We don't need to create a new TEMPLATE_DECL; just use the
one we already had. */
tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl));
@@ -5160,7 +5212,6 @@ push_template_decl_real (tree decl, bool is_friend)
{
tmpl = build_template_decl (decl,
current_template_parms,
- current_template_reqs,
member_template_p);
new_template_p = 1;
@@ -5205,7 +5256,6 @@ push_template_decl_real (tree decl, bool is_friend)
new_tmpl = build_template_decl (decl,
current_template_parms,
- current_template_reqs,
member_template_p);
DECL_TEMPLATE_RESULT (new_tmpl) = decl;
TREE_TYPE (new_tmpl) = TREE_TYPE (decl);
@@ -5378,15 +5428,9 @@ add_inherited_template_parms (tree fn, tree inherited)
tree parms
= tree_cons (size_int (processing_template_decl + 1),
inner_parms, current_template_parms);
- tree tmpl = build_template_decl (fn, parms, NULL_TREE, /*member*/true);
+ tree tmpl = build_template_decl (fn, parms, /*member*/true);
tree args = template_parms_to_args (parms);
- // 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.
- if (tree ci = get_constraints (inherited))
- set_constraints (tmpl, tsubst_constraint_info (ci, args));
-
DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
TREE_TYPE (tmpl) = TREE_TYPE (fn);
DECL_TEMPLATE_RESULT (tmpl) = fn;
@@ -6765,9 +6809,6 @@ is_compatible_template_arg (tree parm, tree arg)
// Note that this is only valid when coerce_template_template_parm is
// true for the innermost template parameters of PARM and ARG. In other
// words, because coercion is successful, this conversion will be valid.
- //
- // BUG: This substitution seems to have broken during an update and no
- // longer works. The resulting expression seems to be the same.
if (parm_cons)
{
tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg));
@@ -10249,12 +10290,12 @@ tsubst_pack_conjunction (tree t, tree args, tsubst_flags_t complain,
// If the resulting expression is type- or value-dependent, then
// return it after setting the result type to bool (so it can be
- // expanded as a conjunction).
- //
- // This happens when instantiating constrained variadic
- // member function templates.
+ // expanded as a conjunction). This happens when instantiating
+ // constrained variadic member function templates. Just rebuild
+ // the dependent pack expansion.
if (instantiation_dependent_expression_p (terms))
{
+ terms = TREE_VEC_ELT (terms, 0);
TREE_TYPE (terms) = boolean_type_node;
return terms;
}
@@ -11053,10 +11094,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
= tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
complain);
- // If constrained, also instantiate the constraints.
- if (tree ci = get_constraints (t))
- set_constraints (r, tsubst_constraint_info (ci, args));
-
if (PRIMARY_TEMPLATE_P (t))
DECL_PRIMARY_TEMPLATE (r) = r;
@@ -11262,15 +11299,24 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
&& !grok_op_properties (r, /*complain=*/false))
RETURN (error_mark_node);
+ // Propagate constraints to the new declaration.
+ if (tree ci = get_constraints (t)) {
+ if (!uses_template_parms (argvec))
+ {
+ tree tr = CI_TEMPLATE_REQS (ci);
+ tree dr = CI_DECLARATOR_REQS (ci);
+ ci = build_constraints (NULL_TREE, conjoin_constraints (tr, dr));
+ }
+ tree new_ci = tsubst_constraint_info (ci, argvec);
+ set_constraints (r, new_ci);
+ }
+
/* Set up the DECL_TEMPLATE_INFO for R. There's no need to do
this in the special friend case mentioned above where
GEN_TMPL is NULL. */
if (gen_tmpl)
{
- if (tree ci = get_constraints (gen_tmpl))
- set_constraints (r, tsubst_constraint_info (ci, argvec));
-
- DECL_TEMPLATE_INFO (r) = build_template_info (gen_tmpl, argvec);
+ DECL_TEMPLATE_INFO (r) = build_template_info (gen_tmpl, argvec);
SET_DECL_IMPLICIT_INSTANTIATION (r);
tree new_r
@@ -19386,8 +19432,10 @@ more_specialized_fn (tree pat1, tree pat2, int len)
// All things still being equal, determine if one is more constrained.
if (lose1 == lose2)
{
- lose1 = !subsumes_constraints (pat1, pat2);
- lose2 = !subsumes_constraints (pat2, pat1);
+ tree c1 = get_constraints (DECL_TEMPLATE_RESULT (pat1));
+ tree c2 = get_constraints (DECL_TEMPLATE_RESULT (pat2));
+ lose1 = !subsumes_constraints (c1, c2);
+ lose2 = !subsumes_constraints (c2, c1);
}
if (lose1 == lose2)
@@ -19834,7 +19882,9 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
spec_args = add_to_template_args (outer_args, spec_args);
// Keep the candidate only if the constraints are satisfied.
- if (check_template_constraints (spec_tmpl, spec_args))
+ tree spec_decl = DECL_TEMPLATE_RESULT (spec_tmpl);
+ tree spec_constr = get_constraints (spec_decl);
+ if (check_constraints (spec_constr, spec_args))
{
list = tree_cons (spec_args, TREE_VALUE (t), list);
TREE_TYPE (list) = TREE_TYPE (t);
@@ -227,12 +227,13 @@ cxx_print_xnode (FILE *file, tree node, int indent)
case CONSTRAINT_INFO:
{
tree_constraint_info *cinfo = (tree_constraint_info *)node;
- if (cinfo->leading_reqs)
- print_node (file, "leading_reqs", cinfo->leading_reqs, indent+4);
- if (cinfo->trailing_reqs)
- print_node (file, "trailing_reqs", cinfo->trailing_reqs, indent+4);
- if (cinfo->assumptions)
- print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
+ if (cinfo->template_reqs)
+ print_node (file, "template_reqs", cinfo->template_reqs, indent+4);
+ if (cinfo->declarator_reqs)
+ print_node (file, "declarator_reqs", cinfo->declarator_reqs, indent+4);
+ print_node (file, "associated_constr",
+ cinfo->associated_constr, indent+4);
+ print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
break;
}
case ARGUMENT_PACK_SELECT:
@@ -2439,6 +2439,8 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
else
{
next = OVL_CHAIN (fn);
+ if (flag_concepts)
+ remove_constraints (fn);
ggc_free (fn);
}
}
@@ -2730,7 +2732,12 @@ finish_template_template_parm (tree aggr, tree identifier)
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
DECL_TEMPLATE_RESULT (tmpl) = decl;
DECL_ARTIFICIAL (decl) = 1;
- set_constraints (tmpl, finish_template_constraints (current_template_reqs));
+
+ // Associate the constraints with the underlying declaration,
+ // not the template.
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree constr = build_constraints (reqs, NULL_TREE);
+ set_constraints (decl, constr);
end_template_decl ();
@@ -2948,7 +2948,8 @@ cp_tree_equal (tree t1, tree t2)
&& cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
case CONSTRAINT_INFO:
- return cp_tree_equal (CI_ASSOCIATED_REQS (t1), CI_ASSOCIATED_REQS (t2));
+ return cp_tree_equal (CI_ASSOCIATED_CONSTRAINTS (t1),
+ CI_ASSOCIATED_CONSTRAINTS (t2));
case TREE_VEC:
{
@@ -11,9 +11,9 @@ template<typename T>
// of whether or not they are dependent. This causes T* to be substituted
// without acutally checking the constraints.
template<typename T>
- using Y = X<T>; // { dg-error "constraints"}
+ using Y = X<T>;
int main()
{
- Y<int> y1; // { dg-error "invalid" }
+ Y<int> y1; // { dg-error "" "" { xfail *-*-* } }
}
@@ -49,12 +49,4 @@ static_assert(S2<char>::value == 0, "");
static_assert(S2<one_type>::value == 1, "");
static_assert(S2<two_type>::value == 2, "");
-// Check that there is no ecsacpe hatch
-template<Two T> struct S4 { };
-template<One T> struct S4<T> { }; // Should never be usable.
-
-S4<two_type>* x4a;
-// S4<one_type>* x4b; // Not suficiently strict
-
-
int main() { }
@@ -8,7 +8,7 @@ template<typename T>
// Check that there is no ecsacpe hatch
template<Two T> struct S4 { };
-template<One T> struct S4<T> { }; // Should never be usable.
+template<One T> struct S4<T> { }; // { dg-error "not more specialized" }
struct one_type { char x[4]; };
@@ -4,17 +4,19 @@ template<typename T>
concept bool C() { return __is_class(T); }
template<typename T>
- struct S1 {
- S1() requires C<T>() { }
- };
+ struct S1 { S1(double) requires C<T>() { } };
+
+struct S2 : S1<int> {
+ using S1<int>::S1;
+};
template<typename T>
- struct S2 : S1<T> {
+ struct S3 : S1<T> {
using S1<T>::S1;
};
struct X { };
int main() {
- S2<X> s;
+ S3<X> s(0.0);
}
@@ -5,7 +5,7 @@ template<typename T>
template<typename T>
struct S1 {
- S1() requires C<T>() { }
+ S1(double) requires C<T>() { }
};
template<typename T>
@@ -14,5 +14,5 @@ template<typename T>
};
int main() {
- S2<int> s; // { dg-error "deleted" }
+ S2<int> s; // { dg-error "deleted function" }
}
@@ -14,5 +14,5 @@ template<typename T>
};
int main() {
- S2<int> s(0); // { dg-error "matching" }
+ S2<int> s(0); // { dg-error "no matching function" }
}
@@ -1,7 +1,7 @@
// { dg-options "-std=c++1z" }
template<typename ... T>
- concept bool C1 = true;
+ concept bool C1 = true; // { dg-message "provided" }
template<int ... N>
concept bool C2 = true;
@@ -17,7 +17,7 @@ template<int N>
template<typename T, typename U = int>
concept bool C5() { return __is_class(U); }
-C1{...A, B} void f1() {}; // { dg-error "no matching concept" }
+C1{...A, B} void f1() {}; // { dg-error "no matching|wrong number" }
C1{A} void f2() {} // { dg-error "match pack" }
C2{A, B} void f3() {}; // { dg-error "match pack" }
C3{...A} void f4() {}; // { dg-error "match pack" }
@@ -11,8 +11,8 @@ template<typename T> constexpr fool p2() { return {}; }
template<typename T>
concept bool C() { return p1<T>() && p2<T>(); }
-template<C T> void f(T x) { } // { dg-error "user-defined" }
+template<C T> void f(T x) { }
int main() {
- f(0); // { dg-error "cannot call" }
+ f(0); // { dg-error "cannot call|predicate constraint" }
}
@@ -11,8 +11,8 @@ template<typename T> constexpr fool p2() { return {}; }
template<typename T>
concept bool C() { return p1<T>() && p2<T>(); }
-template<C T> void f(T x) { } // { dg-error "user-defined" }
+template<C T> void f(T x) { }
int main() {
- f(0); // { dg-error "cannot call" }
+ f(0); // { dg-error "cannot call|predicate constraint" }
}