From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id CCA65385841F; Mon, 12 Sep 2022 21:06:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CCA65385841F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1663016788; bh=9KaBC/dAYV/95/zfIUq9g1vdJX0L+oDFjpZXmbfEUSE=; h=From:To:Subject:Date:From; b=XSehF+Py1+eaDlfhnp5QVyPBcP4pjayk/nDvXx3TZJfYrEgCs9EQH5pevtXBID3hl Q1DK+/1txsL1pFNmpUVCjJY3e6WZIbyhb5atNKPO5LubzQsPHHHfEQdU7vMNAjsI0R UYXSacEqdjrVBMx71LtIkfImoprBM35+dywud2H8= 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-2633] c++: template-id arguments are evaluated [PR101906] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 03381beccb52c0e2c15da3b8b8dfa3bb6eb71df9 X-Git-Newrev: c3ba0eaaa223f7b8208d279e3f39ff134912f9e9 Message-Id: <20220912210628.CCA65385841F@sourceware.org> Date: Mon, 12 Sep 2022 21:06:28 +0000 (GMT) List-Id: https://gcc.gnu.org/g:c3ba0eaaa223f7b8208d279e3f39ff134912f9e9 commit r13-2633-gc3ba0eaaa223f7b8208d279e3f39ff134912f9e9 Author: Patrick Palka Date: Tue Jun 7 14:19:53 2022 -0400 c++: template-id arguments are evaluated [PR101906] Here we're neglecting to clear cp_unevaluated_operand when substituting into the arguments of the alias template-id 'skip<(T(), 0), T>' with T=A, which means cp_unevaluated_operand remains set during mark_used for A::A() and so we don't synthesize it. Later constant evaluation for the substituted template argument '(A(), 0)' (from coerce_template_parms) fails with "'constexpr A::A()' used before its definition" since it was never synthesized. This doesn't happen with a class template because tsubst_aggr_type clears cp_unevaluated_operand during substitution thereof. But since template arguments are generally manifestly constant-evaluated, which in turn are evaluated even in an unevaluated operand, we should be clearing cp_unevaluated_operand more broadly whenever substituting into any set of template arguments. To that end this patch makes us clear it during tsubst_template_args. PR c++/101906 gcc/cp/ChangeLog: * pt.cc (tsubst_template_args): Set cp_evaluated here. (tsubst_aggr_type): Not here. gcc/testsuite/ChangeLog: * g++.dg/template/evaluated1.C: New test. * g++.dg/template/evaluated1a.C: New test. * g++.dg/template/evaluated1b.C: New test. * g++.dg/template/evaluated1c.C: New test. Diff: --- gcc/cp/pt.cc | 6 +++--- gcc/testsuite/g++.dg/template/evaluated1.C | 17 +++++++++++++++++ gcc/testsuite/g++.dg/template/evaluated1a.C | 16 ++++++++++++++++ gcc/testsuite/g++.dg/template/evaluated1b.C | 17 +++++++++++++++++ gcc/testsuite/g++.dg/template/evaluated1c.C | 17 +++++++++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 31e3e391098..4c6b343ab6e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -13616,6 +13616,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (t == error_mark_node) return error_mark_node; + /* In "sizeof(X)" we need to evaluate "I". */ + cp_evaluated ev; + const int len = TREE_VEC_LENGTH (t); tree *elts = XALLOCAVEC (tree, len); int expanded_len_adjust = 0; @@ -13888,9 +13891,6 @@ tsubst_aggr_type (tree t, tree argvec; tree r; - /* In "sizeof(X)" we need to evaluate "I". */ - cp_evaluated ev; - /* Figure out what arguments are appropriate for the type we are trying to find. For example, given: diff --git a/gcc/testsuite/g++.dg/template/evaluated1.C b/gcc/testsuite/g++.dg/template/evaluated1.C new file mode 100644 index 00000000000..41845c65acb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/evaluated1.C @@ -0,0 +1,17 @@ +// PR c++/101906 +// Verify the template arguments of an alias template-id are evaluated even +// in an unevaluated context. +// { dg-do compile { target c++11 } } + +template using skip = T; + +template +constexpr unsigned sizeof_() { + return sizeof(skip<(T(), 0), T>); +} + +struct A { + int m = -1; +}; + +static_assert(sizeof_() == sizeof(A), ""); diff --git a/gcc/testsuite/g++.dg/template/evaluated1a.C b/gcc/testsuite/g++.dg/template/evaluated1a.C new file mode 100644 index 00000000000..78286871004 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/evaluated1a.C @@ -0,0 +1,16 @@ +// PR c++/101906 +// Like unevaluated1.C, but where the unevaluated context is a +// constraint instead of sizeof. +// { dg-do compile { target c++20 } } + +template using voidify = void; + +template +concept constant_value_initializable + = requires { typename voidify<(T(), 0)>; }; + +struct A { + int m = -1; +}; + +static_assert(constant_value_initializable); diff --git a/gcc/testsuite/g++.dg/template/evaluated1b.C b/gcc/testsuite/g++.dg/template/evaluated1b.C new file mode 100644 index 00000000000..7994065ac86 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/evaluated1b.C @@ -0,0 +1,17 @@ +// PR c++/101906 +// Like unevaluated1.C, but using a function template instead of an +// alias template. +// { dg-do compile { target c++14 } } + +template T skip(); + +template +constexpr unsigned sizeof_() { + return sizeof(skip<(T(), 0), T>()); +} + +struct A { + int m = -1; +}; + +static_assert(sizeof_() == sizeof(A), ""); diff --git a/gcc/testsuite/g++.dg/template/evaluated1c.C b/gcc/testsuite/g++.dg/template/evaluated1c.C new file mode 100644 index 00000000000..15c55821c01 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/evaluated1c.C @@ -0,0 +1,17 @@ +// PR c++/101906 +// Like unevaluated1b.C, but using a variable template instead of a +// function template. +// { dg-do compile { target c++14 } } + +template T skip; + +template +constexpr unsigned sizeof_() { + return sizeof(skip<(T(), 0), T>); +} + +struct A { + int m = -1; +}; + +static_assert(sizeof_() == sizeof(A), "");