aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2025-02-26 11:14:00 -0500
committerMarek Polacek <polacek@redhat.com>2025-02-28 12:25:55 -0500
commit22018a4a8caa806a8f673eb0713de16d64d25063 (patch)
tree3bc3d8877a46417d0e0d7279ab4b204002698319 /gcc
parent0bffcd469e68d68ba9c724f515651deff8494b82 (diff)
downloadgcc-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.cc29
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C23
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()](){};
+}