https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118986
--- Comment #10 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The trunk branch has been updated by Marek Polacek <mpola...@gcc.gnu.org>: https://gcc.gnu.org/g:22018a4a8caa806a8f673eb0713de16d64d25063 commit r15-7761-g22018a4a8caa806a8f673eb0713de16d64d25063 Author: Marek Polacek <pola...@redhat.com> Date: Wed Feb 26 11:14:00 2025 -0500 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 <ja...@redhat.com>