From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 4169F3847813; Fri, 9 Jul 2021 14:22:55 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4169F3847813 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 r12-2222] c++: requires-expr with dependent extra args [PR101181] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: f53e66019df819f55d424cc56f8b0ea81c074b55 X-Git-Newrev: 2c699fd29829cd6115f78238dab7cab74f0a5009 Message-Id: <20210709142255.4169F3847813@sourceware.org> Date: Fri, 9 Jul 2021 14:22:55 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Jul 2021 14:22:55 -0000 https://gcc.gnu.org/g:2c699fd29829cd6115f78238dab7cab74f0a5009 commit r12-2222-g2c699fd29829cd6115f78238dab7cab74f0a5009 Author: Patrick Palka Date: Fri Jul 9 10:20:25 2021 -0400 c++: requires-expr with dependent extra args [PR101181] Here we're crashing ultimately because the mechanism for delaying substitution into a requires-expression (and constexpr if and pack expansions) doesn't expect to see dependent args. But we end up capturing dependent args here during substitution into the default template argument as part of coerce_template_parms for the dependent specialization p. This patch enables the commented out code in add_extra_args for handling this situation. This isn't needed for pack expansions (as the accompanying comment points out), and it doesn't seem strictly necessary for constexpr if either, but for requires-expressions delaying even dependent substitution is important for ensuring we don't evaluate requirements out of order. It turns out we also need to make a copy of the arguments when capturing them so that coerce_template_parms doesn't later add to them and form an unexpected cycle (REQUIRES_EXPR_EXTRA_ARGS (t) would indirectly point to t). We also need to make tsubst_template_args handle missing template arguments, since the arguments we capture from coerce_template_parms and are incomplete at that point. PR c++/101181 gcc/cp/ChangeLog: * constraint.cc (tsubst_requires_expr): Pass complain/in_decl to add_extra_args. * cp-tree.h (add_extra_args): Add complain/in_decl parameters. * pt.c (build_extra_args): Make a copy of args. (add_extra_args): Add complain/in_decl parameters. Enable the code for handling the case where the extra arguments are dependent. (tsubst_pack_expansion): Pass complain/in_decl to add_extra_args. (tsubst_template_args): Handle missing template arguments. (tsubst_expr) : Pass complain/in_decl to add_extra_args. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-requires26.C: New test. * g++.dg/cpp2a/lambda-uneval16.C: New test. Diff: --- gcc/cp/constraint.cc | 3 ++- gcc/cp/cp-tree.h | 2 +- gcc/cp/pt.c | 31 ++++++++++++------------ gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C | 18 ++++++++++++++ gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C | 22 +++++++++++++++++ 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 99d3ccc6998..4ee5215df50 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2266,7 +2266,8 @@ tsubst_requires_expr (tree t, tree args, sat_info info) /* A requires-expression is an unevaluated context. */ cp_unevaluated u; - args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args); + args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args, + info.complain, info.in_decl); if (processing_template_decl) { /* We're partially instantiating a generic lambda. Substituting into diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d4810c0c986..b1cf44ecdb8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7291,7 +7291,7 @@ extern void add_mergeable_specialization (bool is_decl, bool is_alias, tree outer, unsigned); extern tree add_to_template_args (tree, tree); extern tree add_outermost_template_args (tree, tree); -extern tree add_extra_args (tree, tree); +extern tree add_extra_args (tree, tree, tsubst_flags_t, tree); extern tree build_extra_args (tree, tree, tsubst_flags_t); /* in rtti.c */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dc0f0b7b58e..cf0ce770d52 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12907,7 +12907,9 @@ extract_local_specs (tree pattern, tsubst_flags_t complain) tree build_extra_args (tree pattern, tree args, tsubst_flags_t complain) { - tree extra = args; + /* Make a copy of the extra arguments so that they won't get changed + out from under us. */ + tree extra = copy_template_args (args); if (local_specializations) if (tree locals = extract_local_specs (pattern, complain)) extra = tree_cons (NULL_TREE, extra, locals); @@ -12918,7 +12920,7 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain) normal template args to ARGS. */ tree -add_extra_args (tree extra, tree args) +add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl) { if (extra && TREE_CODE (extra) == TREE_LIST) { @@ -12938,20 +12940,14 @@ add_extra_args (tree extra, tree args) gcc_assert (!TREE_PURPOSE (extra)); extra = TREE_VALUE (extra); } -#if 1 - /* I think we should always be able to substitute dependent args into the - pattern. If that turns out to be incorrect in some cases, enable the - alternate code (and add complain/in_decl parms to this function). */ - gcc_checking_assert (!uses_template_parms (extra)); -#else - if (!uses_template_parms (extra)) + if (uses_template_parms (extra)) { - gcc_unreachable (); + /* This can happen after dependent substitution into a + requires-expr or a lambda that uses constexpr if. */ extra = tsubst_template_args (extra, args, complain, in_decl); args = add_outermost_template_args (args, extra); } else -#endif args = add_to_template_args (extra, args); return args; } @@ -12977,7 +12973,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, pattern = PACK_EXPANSION_PATTERN (t); /* Add in any args remembered from an earlier partial instantiation. */ - args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args); + args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args, complain, in_decl); levels = TMPL_ARGS_DEPTH (args); @@ -13349,7 +13345,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree orig_arg = TREE_VEC_ELT (t, i); tree new_arg; - if (TREE_CODE (orig_arg) == TREE_VEC) + if (!orig_arg) + new_arg = NULL_TREE; + else if (TREE_CODE (orig_arg) == TREE_VEC) new_arg = tsubst_template_args (orig_arg, args, complain, in_decl); else if (PACK_EXPANSION_P (orig_arg)) { @@ -13399,8 +13397,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) } for (i = 0, out = 0; i < len; i++) { - if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i)) - || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i))) + tree orig_arg = TREE_VEC_ELT (orig_t, i); + if (orig_arg + && (PACK_EXPANSION_P (orig_arg) || ARGUMENT_PACK_P (orig_arg)) && TREE_CODE (elts[i]) == TREE_VEC) { int idx; @@ -18428,7 +18427,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); IF_STMT_CONSTEVAL_P (stmt) = IF_STMT_CONSTEVAL_P (t); if (IF_STMT_CONSTEXPR_P (t)) - args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args); + args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args, complain, in_decl); tmp = RECUR (IF_COND (t)); tmp = finish_if_stmt_cond (tmp, stmt); if (IF_STMT_CONSTEXPR_P (t) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C new file mode 100644 index 00000000000..824d23431f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C @@ -0,0 +1,18 @@ +// PR c++/101181 +// { dg-do compile { target c++20 } } + +template +struct p { using type = void; }; + +template +struct p { using type = typename T::type; }; + +template using P = typename p::type; + +using type1 = P; +using type1 = void; + +struct A { using type = char; }; +using type2 = P; +using type2 = char; diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C new file mode 100644 index 00000000000..1113c6f02b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C @@ -0,0 +1,22 @@ +// PR c++/101181 +// { dg-do compile { target c++20 } } + +template bool { + if constexpr (requires { typename T::type; }) + return true; + return false; + }()> +struct p { using type = void; }; + +template +struct p { using type = typename T::type; }; + +template using P = typename p::type; + +using type1 = P; +using type = void; + +struct A { using type = char; }; +using type2 = P; +using type2 = char;