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.sut...@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" } }