]> git.ipfire.org Git - thirdparty/gcc.git/commit
c++: ICE in replace_decl [PR118986]
authorMarek Polacek <polacek@redhat.com>
Wed, 26 Feb 2025 16:14:00 +0000 (11:14 -0500)
committerMarek Polacek <polacek@redhat.com>
Fri, 28 Feb 2025 17:25:55 +0000 (12:25 -0500)
commit22018a4a8caa806a8f673eb0713de16d64d25063
tree3bc3d8877a46417d0e0d7279ab4b204002698319
parent0bffcd469e68d68ba9c724f515651deff8494b82
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>
gcc/cp/constexpr.cc
gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C [new file with mode: 0644]