This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[c++-concepts] constraints redux
- From: Andrew Sutton <andrew dot n dot sutton at gmail dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>, Jason Merrill <jason at redhat dot com>, Braden Obrzut <admin at maniacsvault dot net>
- Date: Fri, 8 Aug 2014 08:56:26 -0400
- Subject: [c++-concepts] constraints redux
- Authentication-results: sourceware.org; auth=none
This patch revisits the normalization and checking of constraints. In
particular, it ensures that associated constraints are always
normalized so that checking constraints will never instantiate a
concept declaration.
This also removes the constraint check from fn_type_unification as per
discussion in Rapperswil. Candidates whose constraints are not
satisfied are just marked non-viable in overload resolution. This also
clears up an issue where constraints for function templates were being
checked twice during overload resolution.
I also ended up renaming a lot of functions to make them match the
wording the specification. Basically, "requirements -> constraints".
Updated all affected tests.
2014-08-08 Andrew Sutton <andrew.n.sutton@gmail.com>
* gcc/cp/logic.cc (subsumes_constraints_nonnull): Don't re-normalize
constraints, it's already been done.
* gcc/cp/cp-tree.h (*_requirement[s]): Renamed to *_constraint[s] to
reflect wording in specification. Removed reduce_requirements.
* gcc/cp/pt.c (process_template_parm, tsubst_pack_conjunction): Update
from renaming.
(fn_type_unification): Remove constraint check.
* gcc/cp/parser.c (cp_parser_type_parameter,
cp_parser_trailing_requirements,
cp_parser_template_declaration_after_export,
synthesize_implicit_template_parm): Update from renaming.
* gcc/cp/constraint.cc: Renamed a lot of functions to reflect wording
in specification.
(finish_template_constraints): Normalize associated constraints.
(tsubst_constraint_expr): Renamed from instantiate_requirements.
Normalize associated constraints.
(check_satisfied): Return true if the arguments refer to template
parameters.
(all_constraints_satisfied, any_conjunctions_satisfied,
check_requirements): No longer needed.
(check_diagnostic_constraints): Just normalize the expression, don't
decompose it.
Andrew Sutton
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 213667)
+++ gcc/cp/cp-tree.h (working copy)
@@ -6079,10 +6079,6 @@ extern tree maybe_resolve_dummy (tree,
extern tree nonlambda_method_basetype (void);
extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree);
-extern tree finish_template_requirements (tree);
-extern tree save_leading_requirements (tree);
-extern tree save_trailing_requirements (tree);
-extern bool valid_requirements_p (tree);
/* in tree.c */
extern int cp_tree_operand_length (const_tree);
@@ -6415,20 +6411,23 @@ extern void suggest_alternatives_for
extern tree strip_using_decl (tree);
/* in constraint.cc */
-extern tree conjoin_requirements (tree, tree);
-extern tree conjoin_requirements (tree);
-extern tree reduce_requirements (tree);
+extern tree conjoin_constraints (tree, tree);
+extern tree conjoin_constraints (tree);
extern tree get_constraints (tree);
extern void set_constraints (tree, tree);
-extern tree get_shorthand_requirements (tree);
+extern tree get_shorthand_constraints (tree);
extern tree build_concept_check (tree, tree, tree = NULL_TREE);
extern tree build_constrained_parameter (tree, tree, tree = NULL_TREE);
extern bool deduce_constrained_parameter (tree, tree&, tree&);
extern tree resolve_constraint_check (tree);
+extern tree finish_template_constraints (tree);
+extern tree save_leading_constraints (tree);
+extern tree save_trailing_constraints (tree);
+extern bool valid_requirements_p (tree);
extern tree finish_concept_name (tree);
-extern tree finish_shorthand_requirement (tree, tree);
+extern tree finish_shorthand_constraint (tree, tree);
extern tree finish_requires_expr (tree, tree);
extern tree finish_expr_requirement (tree, tree, tree);
extern tree finish_expr_requirement (tree);
@@ -6439,8 +6438,6 @@ extern tree finish_noexcept_requirement
extern tree finish_validexpr_expr (tree);
extern tree finish_validtype_expr (tree);
extern tree finish_constexpr_expr (tree);
-extern tree finish_concept_name (tree);
-extern tree finish_shorthand_requirement (tree, tree);
extern void check_constrained_friend (tree, tree);
@@ -6452,8 +6449,8 @@ extern tree tsubst_expr_req
extern tree tsubst_type_req (tree, tree, tree);
extern tree tsubst_nested_req (tree, tree, tree);
-extern tree instantiate_requirements (tree, tree, bool);
extern tree tsubst_constraint_info (tree, tree);
+extern tree tsubst_constraint_expr (tree, tree, bool);
extern bool check_constraints (tree);
extern bool check_constraints (tree, tree);
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c (revision 213667)
+++ gcc/cp/semantics.c (working copy)
@@ -2704,7 +2704,7 @@ finish_template_template_parm (tree aggr
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
DECL_TEMPLATE_RESULT (tmpl) = decl;
DECL_ARTIFICIAL (decl) = 1;
- set_constraints (tmpl, finish_template_requirements (current_template_reqs));
+ set_constraints (tmpl, finish_template_constraints (current_template_reqs));
end_template_decl ();
Index: gcc/cp/logic.cc
===================================================================
--- gcc/cp/logic.cc (revision 213665)
+++ gcc/cp/logic.cc (working copy)
@@ -506,7 +506,7 @@ subsumes_constraints_nonnull (tree left,
// Check that the required expression in RIGHT is subsumed by each
// subgoal in the assumptions of LEFT.
tree as = CI_ASSUMPTIONS (left);
- tree c = reduce_requirements (CI_ASSOCIATED_REQS (right));
+ tree c = CI_ASSOCIATED_REQS (right);
for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
if (!subsumes_prop (TREE_VEC_ELT (as, i), c))
return false;
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 213667)
+++ gcc/cp/pt.c (working copy)
@@ -3887,7 +3887,7 @@ process_template_parm (tree list, locati
= is_parameter_pack;
// Build requirements for the parameter.
- reqs = finish_shorthand_requirement (parm, constr);
+ reqs = finish_shorthand_constraint (parm, constr);
}
else
{
@@ -3922,7 +3922,7 @@ process_template_parm (tree list, locati
TYPE_CANONICAL (t) = canonical_type_parameter (t);
// Build requirements for the type/template parameter.
- reqs = finish_shorthand_requirement (parm, constr);
+ reqs = finish_shorthand_constraint (parm, constr);
}
DECL_ARTIFICIAL (decl) = 1;
SET_DECL_TEMPLATE_PARM_P (decl);
@@ -4183,7 +4183,7 @@ build_template_decl (tree decl, tree par
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_requirements (constr));
+ set_constraints (tmpl, finish_template_constraints (constr));
return tmpl;
}
@@ -7979,7 +7979,7 @@ lookup_template_class_1 (tree d1, tree a
// anywhere else.
if (complain & tf_error)
{
- error ("template argument deduction failure");
+ error ("template constraint failure");
diagnose_constraints (input_location, gen_tmpl, arglist);
}
return error_mark_node;
@@ -10081,7 +10081,7 @@ tsubst_pack_conjunction (tree t, tree ar
}
// Conjoin requirements. An empty conjunction is equivalent to ture.
- if (tree reqs = conjoin_requirements (terms))
+ if (tree reqs = conjoin_constraints (terms))
return reqs;
else
return boolean_true_node;
@@ -16515,15 +16515,6 @@ fn_type_unification (tree fn,
goto fail;
}
- // All is well so far. Now, check that the template constraints
- // are satisfied.
- if (!check_template_constraints (fn, targs))
- {
- if (explain_p)
- diagnose_constraints (DECL_SOURCE_LOCATION (fn), fn, targs);
- return error_mark_node;
- }
-
/* All is well so far. Now, check:
[temp.deduct]
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 213667)
+++ gcc/cp/parser.c (working copy)
@@ -13642,10 +13642,10 @@ cp_parser_type_parameter (cp_parser* par
// If template requirements are present, parse them.
if (flag_concepts)
{
- tree reqs = get_shorthand_requirements (current_template_parms);
+ tree reqs = get_shorthand_constraints (current_template_parms);
if (tree r = cp_parser_requires_clause_opt (parser))
- reqs = conjoin_requirements (reqs, r);
- current_template_reqs = save_leading_requirements (reqs);
+ 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)
@@ -17103,7 +17103,7 @@ cp_parser_trailing_requirements (cp_pars
push_function_parms (decl);
cp_lexer_consume_token (parser->lexer);
tree reqs = cp_parser_requires_clause (parser);
- current_template_reqs = save_trailing_requirements (reqs);
+ current_template_reqs = save_trailing_constraints (reqs);
finish_scope();
--cp_unevaluated_operand;
}
@@ -24139,10 +24139,10 @@ cp_parser_template_declaration_after_exp
// Manage template requirements
if (flag_concepts)
{
- tree reqs = get_shorthand_requirements (current_template_parms);
+ tree reqs = get_shorthand_constraints (current_template_parms);
if (tree r = cp_parser_requires_clause_opt (parser))
- reqs = conjoin_requirements (reqs, r);
- current_template_reqs = save_leading_requirements (reqs);
+ 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
@@ -33313,7 +33313,7 @@ synthesize_implicit_template_parm (cp_p
// If the invented parameter was constrained, save the constraint.
if (tree reqs = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
- current_template_reqs = save_leading_requirements (reqs);
+ current_template_reqs = save_leading_constraints (reqs);
// Chain the new parameter to the list of implicit parameters.
if (parser->implicit_template_parms)
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 213667)
+++ gcc/cp/decl.c (working copy)
@@ -7542,7 +7542,7 @@ declare_simd_adjust_this (tree *tp, int
// Returns the there leading template requirements if they exist.
static inline tree
-get_leading_template_requirements ()
+get_leading_constraints ()
{
return current_template_reqs ?
CI_LEADING_REQS (current_template_reqs) : NULL_TREE;
@@ -7571,8 +7571,8 @@ adjust_out_of_class_fn_requirements (tre
if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
{
tree reqs = CI_LEADING_REQS (ci);
- if (reqs && !get_leading_template_requirements ())
- current_template_reqs = save_leading_requirements (reqs);
+ if (reqs && !get_leading_constraints ())
+ current_template_reqs = save_leading_constraints (reqs);
}
}
else if (current_template_parms)
@@ -7584,10 +7584,10 @@ adjust_out_of_class_fn_requirements (tre
{
tree r2 = CI_LEADING_REQS (current_template_reqs);
CI_LEADING_REQS (current_template_reqs) =
- conjoin_requirements (r1, r2);
+ conjoin_constraints (r1, r2);
}
else
- current_template_reqs = save_leading_requirements (r1);
+ current_template_reqs = save_leading_constraints (r1);
}
}
}
@@ -7648,7 +7648,7 @@ grokfndecl (tree ctype,
// 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_requirements.
+ // will be fully completed before calling finish_template_constraints.
// verbatim ("%d", processing_template_decl);
if (flag_concepts)
adjust_out_of_class_fn_requirements (ctype);
@@ -7659,7 +7659,7 @@ grokfndecl (tree ctype,
if (current_template_reqs)
{
current_template_reqs
- = finish_template_requirements (current_template_reqs);
+ = finish_template_constraints (current_template_reqs);
set_constraints (decl, current_template_reqs);
}
@@ -12471,7 +12471,7 @@ xref_tag_1 (enum tag_types tag_code, tre
// since a class doesn't have trailing requirements.
if (current_template_reqs)
current_template_reqs =
- finish_template_requirements (current_template_reqs);
+ finish_template_constraints (current_template_reqs);
if (!redeclare_class_template (t,
current_template_parms,
current_template_reqs))
Index: gcc/cp/constraint.cc
===================================================================
--- gcc/cp/constraint.cc (revision 213665)
+++ gcc/cp/constraint.cc (working copy)
@@ -63,11 +63,11 @@ join_requirements (tree_code c, tree a,
// expression with NULL_TREE is an identity operation. That is, for some
// non-null A,
//
-// conjoin_requirements(a, NULL_TREE) == a
+// conjoin_constraints(a, NULL_TREE) == a
//
// If both A and B are NULL_TREE, the result is also NULL_TREE.
tree
-conjoin_requirements (tree a, tree b)
+conjoin_constraints (tree a, tree b)
{
if (a)
return b ? join_requirements (TRUTH_ANDIF_EXPR, a, b) : a;
@@ -80,12 +80,12 @@ conjoin_requirements (tree a, tree b)
// Transform the list of expressions in the T into a conjunction
// of requirements. T must be a TREE_VEC.
tree
-conjoin_requirements (tree t)
+conjoin_constraints (tree t)
{
gcc_assert (TREE_CODE (t) == TREE_VEC);
tree r = NULL_TREE;
for (int i = 0; i < TREE_VEC_LENGTH (t); ++i)
- r = conjoin_requirements (r, TREE_VEC_ELT (t, i));
+ r = conjoin_constraints (r, TREE_VEC_ELT (t, i));
return r;
}
@@ -234,25 +234,25 @@ deduce_constrained_parameter (tree call,
namespace {
// Helper functions
-static tree reduce_node (tree);
-static tree reduce_expr (tree);
-static tree reduce_stmt (tree);
-static tree reduce_decl (tree);
-static tree reduce_misc (tree);
-
-static tree reduce_logical (tree);
-static tree reduce_call (tree);
-static tree reduce_requires (tree);
-static tree reduce_expr_req (tree);
-static tree reduce_type_req (tree);
-static tree reduce_nested_req (tree);
-static tree reduce_template_id (tree);
-static tree reduce_stmt_list (tree);
+tree normalize_constraints (tree);
+tree normalize_node (tree);
+tree normalize_expr (tree);
+tree normalize_stmt (tree);
+tree normalize_decl (tree);
+tree normalize_misc (tree);
+tree normalize_logical (tree);
+tree normalize_call(tree);
+tree normalize_requires (tree);
+tree normalize_expr_req (tree);
+tree normalize_type_req (tree);
+tree normalize_nested_req (tree);
+tree normalize_template_id (tree);
+tree normalize_stmt_list (tree);
// Reduce the requirement T into a logical formula written in terms of
// atomic propositions.
tree
-reduce_node (tree t)
+normalize_node (tree t)
{
switch (TREE_CODE_CLASS (TREE_CODE (t)))
{
@@ -260,16 +260,16 @@ reduce_node (tree t)
case tcc_binary:
case tcc_expression:
case tcc_vl_exp:
- return reduce_expr (t);
+ return normalize_expr (t);
case tcc_statement:
- return reduce_stmt (t);
+ return normalize_stmt (t);
case tcc_declaration:
- return reduce_decl (t);
+ return normalize_decl (t);
case tcc_exceptional:
- return reduce_misc (t);
+ return normalize_misc (t);
// These kinds of expressions are atomic.
case tcc_constant:
@@ -285,37 +285,37 @@ reduce_node (tree t)
// Reduction rules for the expression node T.
tree
-reduce_expr (tree t)
+normalize_expr (tree t)
{
switch (TREE_CODE (t))
{
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
- return reduce_logical (t);
+ return normalize_logical (t);
case CALL_EXPR:
- return reduce_call (t);
+ return normalize_call (t);
case REQUIRES_EXPR:
- return reduce_requires (t);
+ return normalize_requires (t);
case EXPR_REQ:
- return reduce_expr_req (t);
+ return normalize_expr_req (t);
case TYPE_REQ:
- return reduce_type_req (t);
+ return normalize_type_req (t);
case NESTED_REQ:
- return reduce_nested_req (t);
+ return normalize_nested_req (t);
case TEMPLATE_ID_EXPR:
- return reduce_template_id (t);
+ return normalize_template_id (t);
case CAST_EXPR:
- return reduce_node (TREE_VALUE (TREE_OPERAND (t, 0)));
+ return normalize_node (TREE_VALUE (TREE_OPERAND (t, 0)));
case BIND_EXPR:
- return reduce_node (BIND_EXPR_BODY (t));
+ return normalize_node (BIND_EXPR_BODY (t));
// Do not recurse.
case TAG_DEFN:
@@ -330,13 +330,13 @@ reduce_expr (tree t)
// Reduction rules for the statement T.
tree
-reduce_stmt (tree t)
+normalize_stmt (tree t)
{
switch (TREE_CODE (t))
{
// Reduce the returned expression.
case RETURN_EXPR:
- return reduce_node (TREE_OPERAND (t, 0));
+ return normalize_node (TREE_OPERAND (t, 0));
// These statements do not introduce propositions
// in the constraints language. Do not recurse.
@@ -352,7 +352,7 @@ reduce_stmt (tree t)
// Reduction rules for the declaration T.
tree
-reduce_decl (tree t)
+normalize_decl (tree t)
{
switch (TREE_CODE (t))
{
@@ -368,7 +368,7 @@ reduce_decl (tree t)
// Reduction rules for the node T.
tree
-reduce_misc (tree t)
+normalize_misc (tree t)
{
switch (TREE_CODE (t))
{
@@ -378,7 +378,7 @@ reduce_misc (tree t)
return t;
case STATEMENT_LIST:
- return reduce_stmt_list (t);
+ return normalize_stmt_list (t);
default:
gcc_unreachable ();
@@ -391,10 +391,10 @@ reduce_misc (tree t)
// Generate a new expression from the reduced operands. If either operand
// cannot be reduced, then the resulting expression is null.
tree
-reduce_logical (tree t)
+normalize_logical (tree t)
{
- tree l = reduce_expr (TREE_OPERAND (t, 0));
- tree r = reduce_expr (TREE_OPERAND (t, 1));
+ tree l = normalize_expr (TREE_OPERAND (t, 0));
+ tree r = normalize_expr (TREE_OPERAND (t, 1));
if (l && r)
{
t = copy_node (t);
@@ -411,7 +411,7 @@ reduce_logical (tree t)
// If T is a call to a constraint instantiate its definition and
// recursively reduce its returned expression.
tree
-reduce_call (tree t)
+normalize_call (tree t)
{
// Is the function call actually a constraint check?
tree check = resolve_constraint_check (t);
@@ -422,7 +422,7 @@ reduce_call (tree t)
tree args = TREE_PURPOSE (check);
// Reduce the body of the function into the constriants language.
- tree body = reduce_requirements (DECL_SAVED_TREE (fn));
+ tree body = normalize_constraints (DECL_SAVED_TREE (fn));
if (!body)
{
error ("could not inline requirements from %qD", fn);
@@ -430,7 +430,7 @@ reduce_call (tree t)
}
// Instantiate the reduced results using the deduced args.
- tree result = instantiate_requirements (body, args, false);
+ tree result = tsubst_constraint_expr (body, args, false);
if (result == error_mark_node)
{
error ("could not instantiate requirements from %qD", fn);
@@ -450,7 +450,7 @@ reduce_call (tree t)
// Where Foo<T> should actually be written as Foo<T>(). Generate an
// error and suggest the improved writing.
tree
-reduce_template_id (tree t)
+normalize_template_id (tree t)
{
vec<tree, va_gc>* args = NULL;
tree c = finish_call_expr (t, &args, true, false, 0);
@@ -467,25 +467,25 @@ reduce_template_id (tree t)
// Reduce an expression requirement as a conjunction of its
// individual constraints.
tree
-reduce_expr_req (tree t)
+normalize_expr_req (tree t)
{
tree r = NULL_TREE;
for (tree l = TREE_OPERAND (t, 0); l; l = TREE_CHAIN (l))
- r = conjoin_requirements (r, reduce_expr (TREE_VALUE (l)));
+ r = conjoin_constraints (r, normalize_expr (TREE_VALUE (l)));
return r;
}
// Reduce a type requirement by returing its underlying
// constraint.
tree
-reduce_type_req (tree t)
+normalize_type_req (tree t)
{
return TREE_OPERAND (t, 0);
}
// Reduce a nested requireemnt by returing its only operand.
tree
-reduce_nested_req (tree t)
+normalize_nested_req (tree t)
{
return TREE_OPERAND (t, 0);
}
@@ -494,10 +494,10 @@ reduce_nested_req (tree t)
// rewriting the list of requirements so that we end up with a
// list of expressions, some of which may be conjunctions.
tree
-reduce_requires (tree t)
+normalize_requires (tree t)
{
for (tree l = TREE_OPERAND (t, 1); l; l = TREE_CHAIN (l))
- TREE_VALUE (l) = reduce_expr (TREE_VALUE (l));
+ TREE_VALUE (l) = normalize_expr (TREE_VALUE (l));
return t;
}
@@ -510,35 +510,36 @@ reduce_requires (tree t)
// statement. The primary purpose of these rules is to filter those
// non-return statements from the constraints language.
tree
-reduce_stmt_list (tree stmts)
+normalize_stmt_list (tree stmts)
{
tree lhs = NULL_TREE;
tree_stmt_iterator i = tsi_start (stmts);
while (!tsi_end_p (i))
{
- if (tree rhs = reduce_node (tsi_stmt (i)))
- lhs = conjoin_requirements (lhs, rhs);
+ if (tree rhs = normalize_node (tsi_stmt (i)))
+ lhs = conjoin_constraints (lhs, rhs);
tsi_next (&i);
}
return lhs;
}
-} // end namespace
-
// Reduce the requirement REQS into a logical formula written in terms of
// atomic propositions.
tree
-reduce_requirements (tree reqs)
+normalize_constraints (tree reqs)
{
if (!reqs)
return NULL_TREE;
++processing_template_decl;
- tree expr = reduce_node (reqs);
+ tree expr = normalize_node (reqs);
--processing_template_decl;
return expr;
}
+} // end namespace
+
+
// -------------------------------------------------------------------------- //
// Constraint Semantic Processing
//
@@ -567,14 +568,14 @@ set_constraints (tree t, tree ci)
// parameter list PARMS. Note that the requirements are stored in
// the TYPE of each tree node.
tree
-get_shorthand_requirements (tree parms)
+get_shorthand_constraints (tree parms)
{
tree reqs = NULL_TREE;
parms = INNERMOST_TEMPLATE_PARMS (parms);
for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i)
{
tree parm = TREE_VEC_ELT (parms, i);
- reqs = conjoin_requirements(reqs, TEMPLATE_PARM_CONSTRAINTS (parm));
+ reqs = conjoin_constraints(reqs, TEMPLATE_PARM_CONSTRAINTS (parm));
}
return reqs;
}
@@ -590,7 +591,7 @@ build_constraint_info ()
// Create a constraint info object, initialized with the given template
// requirements.
inline tree
-init_leading_requirements (tree reqs)
+init_leading_constraints (tree reqs)
{
tree_constraint_info* ci = build_constraint_info ();
ci->leading_reqs = reqs;
@@ -600,7 +601,7 @@ init_leading_requirements (tree reqs)
// Initialize a constraint info object, initialized with the given
// trailing requirements.
inline tree
-init_trailing_requirements (tree reqs)
+init_trailing_constraints (tree reqs)
{
tree_constraint_info* ci = build_constraint_info ();
ci->trailing_reqs = reqs;
@@ -609,9 +610,9 @@ init_trailing_requirements (tree reqs)
// Upodate the template requiremnets.
inline tree
-update_leading_requirements (tree ci, tree reqs) {
+update_leading_constraints (tree ci, tree reqs) {
tree& current = CI_LEADING_REQS (ci);
- current = conjoin_requirements (current, reqs);
+ current = conjoin_constraints (current, reqs);
return ci;
}
@@ -619,7 +620,7 @@ update_leading_requirements (tree ci, tr
// traling requirements cannot be updated once set: no other reqiurements
// can be found after parsing a trailing requires-clause.
inline tree
-update_trailing_requirements (tree ci, tree reqs) {
+update_trailing_constraints (tree ci, tree reqs) {
gcc_assert(CI_TRAILING_REQS (ci) == NULL_TREE);
CI_TRAILING_REQS (ci) = reqs;
return ci;
@@ -634,14 +635,14 @@ update_trailing_requirements (tree ci, t
// constrained type specifiers in a parameter list. These update the
// template requirements after the template header has been parsed.
tree
-save_leading_requirements (tree reqs)
+save_leading_constraints (tree reqs)
{
if (!reqs || reqs == error_mark_node)
return NULL_TREE;
else if (!current_template_reqs)
- return init_leading_requirements (reqs);
+ return init_leading_constraints (reqs);
else
- return update_leading_requirements (current_template_reqs, reqs);
+ return update_leading_constraints (current_template_reqs, reqs);
}
// Return a constraint info object containing saved trailing requirements.
@@ -649,21 +650,21 @@ save_leading_requirements (tree reqs)
// existing requirements. Otherwise, an empty constraint-info object
// holding only these trailing requirements is returned.
tree
-save_trailing_requirements (tree reqs)
+save_trailing_constraints (tree reqs)
{
if (!reqs || reqs == error_mark_node)
return NULL_TREE;
else if (!current_template_reqs)
- return init_trailing_requirements (reqs);
+ return init_trailing_constraints (reqs);
else
- return update_trailing_requirements (current_template_reqs, reqs);
+ return update_trailing_constraints (current_template_reqs, reqs);
}
// Finish the template requirements, by computing the associated
// constrains (the conjunction of template and trailing requirements),
// and then decomposing that into sets of atomic propositions.
tree
-finish_template_requirements (tree ci)
+finish_template_constraints (tree ci)
{
if (!ci || ci == error_mark_node)
return NULL_TREE;
@@ -678,11 +679,10 @@ finish_template_requirements (tree ci)
// are ill-formed, this is a hard error.
tree r1 = CI_LEADING_REQS (ci);
tree r2 = CI_TRAILING_REQS (ci);
- tree assoc = conjoin_requirements (r1, r2);
- CI_ASSOCIATED_REQS (ci) = assoc;
+ tree reqs = normalize_constraints (conjoin_constraints (r1, r2));
+ CI_ASSOCIATED_REQS (ci) = reqs;
// Decompose those expressions into sets of atomic constraints.
- tree reqs = reduce_requirements (assoc);
CI_ASSUMPTIONS (ci) = decompose_assumptions (reqs);
return ci;
}
@@ -994,7 +994,7 @@ build_constrained_parameter (tree fn, tr
return decl;
}
-// Create a requirement expression for the given DECL that evaluates the
+// Create a constraint expression for the given DECL that evaluates the
// requirements specified by CONSTR, a TYPE_DECL that contains all the
// information necessary to build the requirements (see finish_concept_name
// for the layout of that TYPE_DECL).
@@ -1002,7 +1002,7 @@ build_constrained_parameter (tree fn, tr
// Note that the constraints are neither reduced nor decomposed. That is
// done only after the requires clause has been parsed (or not).
tree
-finish_shorthand_requirement (tree decl, tree constr)
+finish_shorthand_constraint (tree decl, tree constr)
{
// No requirements means no constraints.
if (!constr)
@@ -1176,7 +1176,7 @@ tsubst_expr_req (tree t, tree args, tree
for (tree l = TREE_OPERAND (t, 0); l; l = TREE_CHAIN (l))
{
tree e = tsubst_expr (TREE_VALUE (l), args, tf_none, in_decl, false);
- r = conjoin_requirements (r, e);
+ r = conjoin_constraints (r, e);
}
return r;
}
@@ -1205,7 +1205,7 @@ tsubst_nested_req (tree t, tree args, tr
// if parsing a template declaration, which causes the resulting expression
// to not be folded.
tree
-instantiate_requirements (tree reqs, tree args, bool do_not_fold)
+tsubst_constraint_expr (tree reqs, tree args, bool do_not_fold)
{
cp_unevaluated guard;
if (do_not_fold)
@@ -1227,17 +1227,16 @@ tsubst_constraint_info (tree ci, tree ar
// Substitute into the various constraint fields.
tree_constraint_info* result = build_constraint_info ();
if (tree r = CI_LEADING_REQS (ci))
- result->leading_reqs = instantiate_requirements (r, args, true);
+ result->leading_reqs = tsubst_constraint_expr (r, args, true);
if (tree r = CI_TRAILING_REQS (ci))
- result->trailing_reqs = instantiate_requirements (r, args, true);
+ result->trailing_reqs = tsubst_constraint_expr (r, args, true);
- // Build the associated requiremnts.
- result->associated_reqs =
- conjoin_requirements (result->leading_reqs, result->trailing_reqs);
+ // Build the normalized associated requiremnts.
+ tree r = conjoin_constraints (result->leading_reqs, result->trailing_reqs);
+ result->associated_reqs = normalize_constraints (r);
// Analyze the resulting constraints.
// TODO: Is this actually necessary if the constraints are non-dependent?
- // Presumably not since we'd never actually look at them, right?
result->assumptions = decompose_assumptions (result->associated_reqs);
return (tree)result;
}
@@ -1255,8 +1254,13 @@ namespace {
static bool
check_satisfied (tree req, tree args)
{
+ // If any arguments are dependent, then we can't check the
+ // requirements. Just return true.
+ if (args && uses_template_parms (args))
+ return true;
+
// Instantiate and evaluate the requirements.
- req = instantiate_requirements (req, args, false);
+ req = tsubst_constraint_expr (req, args, false);
if (req == error_mark_node)
return false;
@@ -1269,45 +1273,6 @@ check_satisfied (tree req, tree args)
return result == boolean_true_node;
}
-// Returns true iff all atomic constraints in the list are satisfied.
-static bool
-all_constraints_satisfied (tree reqs, tree args)
-{
- int n = TREE_VEC_LENGTH (reqs);
- for (int i = 0; i < n; ++i)
- {
- tree req = TREE_VEC_ELT (reqs, i);
- if (!check_satisfied (req, args))
- return false;
- }
- return true;
-}
-
-// Returns true if any conjunction of assumed requirements are satisfied.
-static bool
-any_conjunctions_satisfied (tree reqs, tree args)
-{
- int n = TREE_VEC_LENGTH (reqs);
- for (int i = 0; i < n; ++i)
- {
- tree con = TREE_VEC_ELT (reqs, i);
- if (all_constraints_satisfied (con, args))
- return true;
- }
- return false;
-}
-
-// Returns true iff the assumptions in REQS are satisfied.
-static inline bool
-check_requirements (tree reqs, tree args)
-{
- // If any arguments are dependent, then we can't check the
- // requirements. Just return true.
- if (args && uses_template_parms (args))
- return true;
-
- return any_conjunctions_satisfied (reqs, args);
-}
} // namespace
// Check the instantiated declaration constraints.
@@ -1325,7 +1290,7 @@ check_constraints (tree cinfo)
// all remaining expressions that are not constant expressions
// (e.g., template-id expressions).
else
- return check_requirements (CI_ASSUMPTIONS (cinfo), NULL_TREE);
+ return check_satisfied (CI_ASSOCIATED_REQS (cinfo), NULL_TREE);
}
// Check the constraints in CINFO against the given ARGS, returning
@@ -1340,7 +1305,7 @@ check_constraints (tree cinfo, tree args
else if (!valid_requirements_p (cinfo))
return false;
else {
- return check_requirements (CI_ASSUMPTIONS (cinfo), args);
+ return check_satisfied (CI_ASSOCIATED_REQS (cinfo), args);
}
}
@@ -1353,13 +1318,6 @@ check_template_constraints (tree t, tree
return check_constraints (get_constraints (t), args);
}
-bool
-check_diagnostic_constraints (tree t, tree args)
-{
- tree reqs = decompose_assumptions (reduce_requirements (t));
- return check_requirements (reqs, args);
-}
-
// -------------------------------------------------------------------------- //
// Constraint Relations
//
@@ -1413,6 +1371,15 @@ more_constrained (tree a, tree b) {
namespace {
+// Given an arbitrary constraint expression, normalize it and
+// then check it. We have to normalize so we don't accidentally
+// instantiate concept declarations.
+inline bool
+check_diagnostic_constraints (tree reqs, tree args)
+{
+ return check_satisfied (normalize_constraints (reqs), args);
+}
+
void diagnose_node (location_t, tree, tree);
// Diagnose a constraint failure for type trait expressions.
@@ -1422,7 +1389,7 @@ diagnose_trait (location_t loc, tree t,
if (check_diagnostic_constraints (t, args))
return;
- tree subst = instantiate_requirements (t, args, true);
+ tree subst = tsubst_constraint_expr (t, args, true);
if (subst == error_mark_node)
{
@@ -1527,7 +1494,7 @@ diagnose_check (location_t loc, tree t,
// Locally instantiate the body with the call's template args,
// and recursively diagnose.
- body = instantiate_requirements (body, targs, true);
+ body = tsubst_constraint_expr (body, targs, true);
diagnose_node (loc, body, args);
}
@@ -1554,7 +1521,7 @@ diagnose_requires (location_t loc, tree
if (check_diagnostic_constraints (t, args))
return;
- tree subst = instantiate_requirements (t, args, true);
+ tree subst = tsubst_constraint_expr (t, args, true);
// Print the header for the requires expression.
tree parms = TREE_OPERAND (subst, 0);
Index: gcc/testsuite/g++.dg/concepts/req2.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/req2.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/req2.C (working copy)
@@ -16,6 +16,6 @@ void f2(auto a)
struct S { } s;
int main() {
- f1(0); // { dg-error "matching" }
- f2((void*)0); // { dg-error "matching" }
+ f1(0); // { dg-error "cannot call" }
+ f2((void*)0); // { dg-error "cannot call" }
}
Index: gcc/testsuite/g++.dg/concepts/alias3.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/alias3.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/alias3.C (working copy)
@@ -9,5 +9,5 @@ template<typename T>
int main()
{
- X<int> x1; // { dg-error "deduction|invalid" }
+ X<int> x1; // { dg-error "constraint|invalid" }
}
Index: gcc/testsuite/g++.dg/concepts/class2.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/class2.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/class2.C (working copy)
@@ -9,6 +9,6 @@ template<typename T>
struct X { };
-S<int> sx; // { dg-error "deduction|invalid" }
+S<int> sx; // { dg-error "constraint|invalid" }
int main() { }
Index: gcc/testsuite/g++.dg/concepts/class6.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/class6.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/class6.C (working copy)
@@ -13,6 +13,6 @@ template<One T> struct S4<T> { }; // Sho
struct one_type { char x[4]; };
// Constraints are checked even when decls are not instantiatied.
-S4<one_type>* x4b; // { dg-error "deduction|invalid" }
+S4<one_type>* x4b; // { dg-error "constraint|invalid" }
int main() { }
Index: gcc/testsuite/g++.dg/concepts/class8.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/class8.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/class8.C (working copy)
@@ -7,7 +7,7 @@ template<C T> struct S;
struct X { };
-// Not a valid declaration, int does not satisfy C.
-template<> struct S<int> { }; // { dg-error "deduction" }
+// Not a valid explicit specialization, int does not satisfy C.
+template<> struct S<int> { }; // { dg-error "constraint" }
int main() { }
Index: gcc/testsuite/g++.dg/concepts/mem-concept-err.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/mem-concept-err.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/mem-concept-err.C (working copy)
@@ -30,8 +30,8 @@ template<typename T>
};
int main() {
- f1('a'); // { dg-error "matching" }
- f2(0); // { dg-error "matching" }
+ f1('a'); // { dg-error "cannot call" }
+ f2(0); // { dg-error "cannot call" }
S<int> s;
s.f1('a'); // { dg-error "matching" }
Index: gcc/testsuite/g++.dg/concepts/explicit-inst1.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/explicit-inst1.C (revision 0)
+++ gcc/testsuite/g++.dg/concepts/explicit-inst1.C (revision 0)
@@ -0,0 +1,14 @@
+// { dg-options "-std=c++1z" }
+
+template<typename T>
+ concept bool C() { return __is_class(T); }
+
+template<typename T>
+ requires C<T>()
+ struct Test { };
+
+struct X { };
+
+template struct Test<X>;
+
+int main() { }
Index: gcc/testsuite/g++.dg/concepts/explicit-inst2.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/explicit-inst2.C (revision 0)
+++ gcc/testsuite/g++.dg/concepts/explicit-inst2.C (revision 0)
@@ -0,0 +1,12 @@
+// { dg-options "-std=c++1z" }
+
+template<typename T>
+ concept bool C() { return __is_class(T); }
+
+template<typename T>
+ requires C<T>()
+ struct Test { };
+
+template struct Test<int>; // { dg-error "constraint" }
+
+int main() { }
Index: gcc/testsuite/g++.dg/concepts/fn2.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/fn2.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/fn2.C (working copy)
@@ -10,9 +10,9 @@ template<typename T>
// Non-dependent args are checked even in dependent scope.
template<typename T>
void h(T x) {
- f(0); // { dg-error "matching" }
+ f(0); // { dg-error "cannot call" }
}
int main() {
- f(0); // { dg-error "matching" }
+ f(0); // { dg-error "cannot call" }
}
Index: gcc/testsuite/g++.dg/concepts/traits2.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/traits2.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/traits2.C (working copy)
@@ -79,21 +79,21 @@ template<Enum T> void f18();
int main() {
- f1<void>(); // { dg-error "matching" }
- f2<void>(); // { dg-error "matching" }
- f3<void>(); // { dg-error "matching" }
- f4<void>(); // { dg-error "matching" }
- f5<void>(); // { dg-error "matching" }
- f6<void>(); // { dg-error "matching" }
- f7<void>(); // { dg-error "matching" }
- f8<void>(); // { dg-error "matching" }
- f9<void>(); // { dg-error "matching" }
- f10<void>(); // { dg-error "matching" }
- f11<void>(); // { dg-error "matching" }
- f12<void>(); // { dg-error "matching" }
- f13<void>(); // { dg-error "matching" }
- f14<void>(); // { dg-error "matching" }
- f15<void>(); // { dg-error "matching" }
- f16<void>(); // { dg-error "matching" }
- f17<void>(); // { dg-error "matching" }
+ f1<void>(); // { dg-error "cannot call" }
+ f2<void>(); // { dg-error "cannot call" }
+ f3<void>(); // { dg-error "cannot call" }
+ f4<void>(); // { dg-error "cannot call" }
+ f5<void>(); // { dg-error "cannot call" }
+ f6<void>(); // { dg-error "cannot call" }
+ f7<void>(); // { dg-error "cannot call" }
+ f8<void>(); // { dg-error "cannot call" }
+ f9<void>(); // { dg-error "cannot call" }
+ f10<void>(); // { dg-error "cannot call" }
+ f11<void>(); // { dg-error "cannot call" }
+ f12<void>(); // { dg-error "cannot call" }
+ f13<void>(); // { dg-error "cannot call" }
+ f14<void>(); // { dg-error "cannot call" }
+ f15<void>(); // { dg-error "cannot call" }
+ f16<void>(); // { dg-error "cannot call" }
+ f17<void>(); // { dg-error "cannot call" }
}
Index: gcc/testsuite/g++.dg/concepts/fn5.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/fn5.C (revision 213665)
+++ gcc/testsuite/g++.dg/concepts/fn5.C (working copy)
@@ -15,9 +15,9 @@ void f(Same<int> q) { }
void g(Type a, Same<decltype(a)> b) { }
int main() {
- S1<char> s1; // { dg-error "deduction|invalid" }
- S2<int, char> s2; // { dg-error "deduction|invalid" }
+ S1<char> s1; // { dg-error "constraint|invalid" }
+ S2<int, char> s2; // { dg-error "constraint|invalid" }
- f('a'); // { dg-error "matching" }
- g(0, 'a'); // { dg-error "matching" }
+ f('a'); // { dg-error "cannot" }
+ g(0, 'a'); // { dg-error "cannot" }
}