diff options
author | Marek Polacek <polacek@redhat.com> | 2025-02-26 11:14:00 -0500 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2025-02-28 12:25:55 -0500 |
commit | 22018a4a8caa806a8f673eb0713de16d64d25063 (patch) | |
tree | 3bc3d8877a46417d0e0d7279ab4b204002698319 /gcc | |
parent | 0bffcd469e68d68ba9c724f515651deff8494b82 (diff) | |
download | gcc-22018a4a8caa806a8f673eb0713de16d64d25063.zip gcc-22018a4a8caa806a8f673eb0713de16d64d25063.tar.gz gcc-22018a4a8caa806a8f673eb0713de16d64d25063.tar.bz2 |
c++: ICE in replace_decl [PR118986]
Yet another problem that started with r15-6052, compile time evaluation of
prvalues.
cp_fold_r/TARGET_EXPR sees:
TARGET_EXPR <D.2701, <<< Unknown tree: expr_stmt
D.2701.__p = TARGET_EXPR <D.2684, <<< Unknown tree: aggr_init_expr
3
f1
D.2684 >>>> >>>>
so when we call maybe_constant_init, the object we're initializing is D.2701,
and the init is the expr_stmt. We unwrap the EXPR_STMT/INIT_EXPR/TARGET_EXPR
in maybe_constant_init_1 and so end up evaluating the f1 call. But f1 returns
c2 whereas the type of D.2701 is ._anon_0 -- the closure.
So then we crash in replace_decl on:
gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (decl), TREE_TYPE (replacement)));
due to the mismatched types.
cxx_eval_outermost_constant_expr is already ready for the types to be
different, in which case the result isn't constant. But replace_decl
is called before that check.
I'm leaving the assert in replace_decl on purpose, maybe we'll find
another use for it.
PR c++/118986
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_call_expression): Check that the types match
before calling replace_decl, if not, set *non_constant_p.
(maybe_constant_init_1): Don't strip INIT_EXPR if it would change the
type of the expression.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/constexpr-prvalue1.C: New test.
Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constexpr.cc | 29 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C | 23 |
2 files changed, 43 insertions, 9 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 3cbc9c8..97c227d 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -3388,16 +3388,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, /* Rewrite all occurrences of the function's RESULT_DECL with the current object under construction. */ - if (!*non_constant_p && ctx->object + if (!*non_constant_p + && ctx->object && CLASS_TYPE_P (TREE_TYPE (res)) && !is_empty_class (TREE_TYPE (res))) - if (replace_decl (&result, res, ctx->object)) - { - cacheable = false; - result = cxx_eval_constant_expression (ctx, result, lval, - non_constant_p, - overflow_p); - } + { + if (!same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (res), TREE_TYPE (ctx->object))) + *non_constant_p = true; + else if (replace_decl (&result, res, ctx->object)) + { + cacheable = false; + result = cxx_eval_constant_expression (ctx, result, lval, + non_constant_p, + overflow_p); + } + } /* Only cache a permitted result of a constant expression. */ if (cacheable && !reduced_constant_expression_p (result)) @@ -9605,7 +9611,12 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, if (TREE_CODE (t) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (t))) t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == INIT_EXPR) + /* If the types don't match, the INIT_EXPR is initializing a subobject of + DECL and losing that information would cause mischief later. */ + if (TREE_CODE (t) == INIT_EXPR + && (!decl + || same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (decl), + TREE_TYPE (t)))) t = TREE_OPERAND (t, 1); if (TREE_CODE (t) == TARGET_EXPR) t = TARGET_EXPR_INITIAL (t); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C new file mode 100644 index 0000000..f4e704d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C @@ -0,0 +1,23 @@ +// PR c++/118986 +// { dg-do compile { target c++20 } } +// { dg-options "-O" } + +struct c1 { + constexpr c1(int *ptr) {} +}; +struct c2 { + c1 _M_t; + constexpr ~c2() {} +}; +constexpr inline +c2 f1 () +{ + return c2(new int); +} + +void +f () +{ + auto l = [p = f1()](){}; + [p = f1()](){}; +} |