Re: [PATCH 2/2] c++: is_const_eval init folding inside lambda scope [PR126483]
Jason Merrill <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On 8/6/26 10:59 AM, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk/backports?
OK.
> -- >8 --
>
> Here when processing a's copy-initialization we overeagerly fold its
> initializer as if the lambda scope is not constexpr, and thus assume
> is_const_eval() is false. Subsequent constant evaluation of the lambda
> gives the wrong answer due to this premature folding.
>
> The culprit cp_fully_fold_init call is guarded by DECL_DECLARED_CONSTEXPR_P
> but that isn't set on maybe-constexpr lambdas until the lambda is fully
> parsed and its body is checked as a whole for constexpr suitability.
> The call needs to instead be guarded by maybe_constexpr_fn which considers
> such lambdas (although it considers all lambdas to be maybe-constexpr
> even fully parsed ones that have been deemed non-constexpr).
>
> This however means we no longer fold a's copy-init even for the runtime
> version of the lambda body, hence the is_constant_evaluated3b xfail.
> Making maybe_constexpr_fn distinguish between fully parsed constexpr and
> non-constexpr lambdas doesn't help because we don't hit this code path
> again and cp_fold_function can't seem to fold the copy-init form:
>
> struct A a1;
> <<cleanup_point <<< Unknown tree: expr_stmt
> (void) (a1 = <<< Unknown tree: aggr_init_expr
> 5
> __ct_comp
> D.3052
> (struct A *) <<< Unknown tree: void_cst >>>
> 42 >>>) >>>>>;
>
> whereas (after r14-6506) it does fold direct-init etc which is expressed
> as:
>
> struct A a3;
> <<cleanup_point <<< Unknown tree: expr_stmt
> A::A (&a3, NON_LVALUE_EXPR <42>) >>>>>;
>
> Marek's prvalue folding patch r15-6052 doesn't seem to help because
> naturally it looks for TARGET_EXPR and we don't have one here. It
> should be possible to have cp_fold_function fold this but I haven't
> looked into it. It would fix the xfail in is_constant_evaluated3{a,b}.
>
> PR c++/126483
>
> gcc/cp/ChangeLog:
>
> * typeck2.cc (store_init_value): Check maybe_constexpr_fn
> instead of DECL_DECLARED_CONSTEXPR_P.
>
> gcc/testsuite/ChangeLog:
>
> * gcc/testsuite/g++.dg/opt/is_constant_evaluated3b.C: xfail
> a1 initializer folding.
> * g++.dg/cpp2a/is-constant-evaluated16.C: New test.
> ---
> gcc/cp/typeck2.cc | 2 +-
> .../g++.dg/cpp2a/is-constant-evaluated16.C | 20 +++++++++++++++++++
> .../g++.dg/opt/is_constant_evaluated3b.C | 2 +-
> 3 files changed, 22 insertions(+), 2 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated16.C
>
> diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> index 6c4ed50cb94e..62f583dcf405 100644
> --- a/gcc/cp/typeck2.cc
> +++ b/gcc/cp/typeck2.cc
> @@ -1129,7 +1129,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
> that might fold away something that needs to be diagnosed at constexpr
> evaluation time. */
> if (!current_function_decl
> - || !DECL_DECLARED_CONSTEXPR_P (current_function_decl)
> + || !maybe_constexpr_fn (current_function_decl)
> || TREE_STATIC (decl))
> value = cp_fully_fold_init (value);
>
> diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated16.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated16.C
> new file mode 100644
> index 000000000000..c727967673e3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated16.C
> @@ -0,0 +1,20 @@
> +// PR c++/126483
> +// { dg-do compile { target c++17 } }
> +
> +struct A {
> + int m;
> + constexpr A(int n) : m(__builtin_is_constant_evaluated() ? 42 : n) { }
> +};
> +
> +constexpr auto v = [] {
> + A a = 0;
> + return a.m;
> +};
> +static_assert(v() == 42);
> +
> +template<class>
> +constexpr auto vt = [] {
> + A a = 0;
> + return a.m;
> +};
> +static_assert(vt<void>() == 42);
> diff --git a/gcc/testsuite/g++.dg/opt/is_constant_evaluated3b.C b/gcc/testsuite/g++.dg/opt/is_constant_evaluated3b.C
> index ff708e23832b..ac6d21d632e1 100644
> --- a/gcc/testsuite/g++.dg/opt/is_constant_evaluated3b.C
> +++ b/gcc/testsuite/g++.dg/opt/is_constant_evaluated3b.C
> @@ -17,7 +17,7 @@ auto f = [] {
> A a5{};
> };
>
> -// { dg-final { scan-tree-dump "a1 = {\\.n=42, \\.m=0}" "original" } }
> +// { dg-final { scan-tree-dump "a1 = {\\.n=42, \\.m=0}" "original" { xfail *-*-* } } }
> // { dg-final { scan-tree-dump "a2 = {\\.n=42, \\.m=0}" "original" } }
> // { dg-final { scan-tree-dump "a3 = {\\.n=42, \\.m=0}" "original" } }
> // { dg-final { scan-tree-dump "a4 = {\\.n=42, \\.m=0}" "original" } }