From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 514AF384AB6A; Mon, 15 Apr 2024 15:31:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 514AF384AB6A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1713195087; bh=SR7CbcTkVN7nkebrU8eFvVUiIplOwTo1Vs13bKgqiDo=; h=From:To:Subject:Date:From; b=hEIRenWZbohIEcN5XCQH5KMeURogUsWMsIHADJ4yRhIX3Zd9/5TJeIcWe8pRd4ATR bdrTKyU/PEp4HffRzeHFIEv/6AHZwEmFg16OIw1HGU5oqAYO/PUdXO1014+DhdpKto 1Gxd3Vy6g/Mv+NZr1c1h1SD7VA9NYYp+WeuwEByc= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-8608] c++: requires-exprs and partial constraint subst [PR110006] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/releases/gcc-13 X-Git-Oldrev: e534b2280c8522a67532417681a0340bcc5e1c9b X-Git-Newrev: 38c2679ff9330d3ac1d5d86459294446733a435a Message-Id: <20240415153127.514AF384AB6A@sourceware.org> Date: Mon, 15 Apr 2024 15:31:27 +0000 (GMT) List-Id: https://gcc.gnu.org/g:38c2679ff9330d3ac1d5d86459294446733a435a commit r13-8608-g38c2679ff9330d3ac1d5d86459294446733a435a Author: Patrick Palka Date: Fri Feb 2 19:07:08 2024 -0500 c++: requires-exprs and partial constraint subst [PR110006] In r11-3261-gb28b621ac67bee we made tsubst_requires_expr never partially substitute into a requires-expression so as to avoid checking its requirements out of order during e.g. generic lambda regeneration. These PRs however illustrate that we still sometimes do need to partially substitute into a requires-expression, in particular when it appears in associated constraints that we're directly substituting for sake of declaration matching or dguide constraint rewriting. In these cases we're being called from tsubst_constraint during which processing_constraint_expression_p is true, so this patch checks this predicate to control whether we defer substitution or partially substitute. In turn, we now need to propagate semantic tsubst flags through tsubst_requires_expr rather than just using tf_none, notably for sake of dguide constraint rewriting which sets tf_dguide. PR c++/110006 PR c++/112769 gcc/cp/ChangeLog: * constraint.cc (subst_info::quiet): Accomodate non-diagnostic tsubst flags. (tsubst_valid_expression_requirement): Likewise. (tsubst_simple_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_type_requirement_1): Accomodate non-diagnostic tsubst flags. (tsubst_type_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_compound_requirement): Likewise. Accomodate non-diagnostic tsubst flags. (tsubst_nested_requirement): Likewise. (tsubst_requires_expr): Don't defer partial substitution when processing_constraint_expression_p is true, in which case return a substituted REQUIRES_EXPR. * pt.cc (tsubst_expr) : Accomodate non-diagnostic tsubst flags. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias18.C: New test. * g++.dg/cpp2a/concepts-friend16.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 686b5eb9c9ee623a604dde5c49fa11c23f384c62) Diff: --- gcc/cp/constraint.cc | 56 +++++++++++++++++----- gcc/cp/pt.cc | 3 +- .../g++.dg/cpp2a/class-deduction-alias18.C | 13 +++++ gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C | 25 ++++++++++ 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 273d15ab097..971619eabea 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -85,7 +85,7 @@ struct subst_info /* True if we should not diagnose errors. */ bool quiet() const { - return complain == tf_none; + return !(complain & tf_warning_or_error); } /* True if we should diagnose errors. */ @@ -1999,8 +1999,9 @@ hash_placeholder_constraint (tree c) static tree tsubst_valid_expression_requirement (tree t, tree args, sat_info info) { - tree r = tsubst_expr (t, args, tf_none, info.in_decl); - if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node) + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst_expr (t, args, quiet, info.in_decl); + if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node) return r; if (info.diagnose_unsatisfaction_p ()) @@ -2036,6 +2037,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) tree expr = tsubst_valid_expression_requirement (t0, args, info); if (expr == error_mark_node) return error_mark_node; + if (processing_template_decl) + return finish_simple_requirement (EXPR_LOCATION (t), expr); return boolean_true_node; } @@ -2045,7 +2048,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) static tree tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc) { - tree r = tsubst (t, args, tf_none, info.in_decl); + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst (t, args, quiet, info.in_decl); if (r != error_mark_node) return r; @@ -2076,6 +2080,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info) tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t)); if (type == error_mark_node) return error_mark_node; + if (processing_template_decl) + return finish_type_requirement (EXPR_LOCATION (t), type); return boolean_true_node; } @@ -2132,9 +2138,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) location_t loc = cp_expr_loc_or_input_loc (expr); + subst_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); + /* Check the noexcept condition. */ bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t); - if (noexcept_p && !expr_noexcept_p (expr, tf_none)) + if (noexcept_p && !expr_noexcept_p (expr, quiet.complain)) { if (info.diagnose_unsatisfaction_p ()) inform (loc, "%qE is not %", expr); @@ -2147,8 +2155,6 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) if (type == error_mark_node) return error_mark_node; - subst_info quiet (tf_none, info.in_decl); - /* Check expression against the result type. */ if (type) { @@ -2190,6 +2196,9 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) } } + if (processing_template_decl) + return finish_compound_requirement (EXPR_LOCATION (t), + expr, type, noexcept_p); return boolean_true_node; } @@ -2198,7 +2207,16 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) static tree tsubst_nested_requirement (tree t, tree args, sat_info info) { - sat_info quiet (tf_none, info.in_decl); + if (processing_template_decl) + { + tree req = TREE_OPERAND (t, 0); + req = tsubst_constraint (req, args, info.complain, info.in_decl); + if (req == error_mark_node) + return error_mark_node; + return finish_nested_requirement (EXPR_LOCATION (t), req); + } + + sat_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); tree result = constraint_satisfaction_value (t, args, quiet); if (result == boolean_true_node) return boolean_true_node; @@ -2338,18 +2356,25 @@ tsubst_requires_expr (tree t, tree args, sat_info info) args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args, info.complain, info.in_decl); - if (processing_template_decl) + if (processing_template_decl + && !processing_constraint_expression_p ()) { /* We're partially instantiating a generic lambda. Substituting into this requires-expression now may cause its requirements to get checked out of order, so instead just remember the template - arguments and wait until we can substitute them all at once. */ + arguments and wait until we can substitute them all at once. + + Except if this requires-expr is part of associated constraints + that we're substituting into directly (for e.g. declaration + matching or dguide constraint rewriting), in which case we need + to partially substitute. */ t = copy_node (t); REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain); return t; } - if (tree parms = REQUIRES_EXPR_PARMS (t)) + tree parms = REQUIRES_EXPR_PARMS (t); + if (parms) { parms = tsubst_constraint_variables (parms, args, info); if (parms == error_mark_node) @@ -2357,10 +2382,13 @@ tsubst_requires_expr (tree t, tree args, sat_info info) } tree result = boolean_true_node; + if (processing_template_decl) + result = NULL_TREE; for (tree reqs = REQUIRES_EXPR_REQS (t); reqs; reqs = TREE_CHAIN (reqs)) { tree req = TREE_VALUE (reqs); - if (tsubst_requirement (req, args, info) == error_mark_node) + req = tsubst_requirement (req, args, info); + if (req == error_mark_node) { result = boolean_false_node; if (info.diagnose_unsatisfaction_p ()) @@ -2368,7 +2396,11 @@ tsubst_requires_expr (tree t, tree args, sat_info info) else break; } + else if (processing_template_decl) + result = tree_cons (NULL_TREE, req, result); } + if (processing_template_decl && result != boolean_false_node) + result = finish_requires_expr (EXPR_LOCATION (t), parms, nreverse (result)); return result; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f5e6541fd0f..a768d11c82f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21783,7 +21783,8 @@ tsubst_copy_and_build (tree t, case REQUIRES_EXPR: { - tree r = tsubst_requires_expr (t, args, tf_none, in_decl); + complain &= ~tf_warning_or_error; + tree r = tsubst_requires_expr (t, args, complain, in_decl); RETURN (r); } diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C new file mode 100644 index 00000000000..0bb11bb944c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C @@ -0,0 +1,13 @@ +// PR c++/112769 +// { dg-do compile { target c++20 } } + +template +struct type +{ + type(T) requires requires { T{0}; }; +}; + +template +using alias = type<0, T>; + +alias foo{123}; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C new file mode 100644 index 00000000000..18974eeb172 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C @@ -0,0 +1,25 @@ +// PR c++/110006 +// { dg-do compile { target c++20 } } + +template +class s; + +template +void constraint(s const&, int&); + +template +U function(s const x) + requires requires (U& u) { constraint(x, u); }; + +template +class s +{ + template + friend U function(s const x) + requires requires (U& u) { constraint(x, u); }; +}; + +int f(s q) +{ + return function(q); // { dg-bogus "ambiguous" } +}