On 2/26/25 2:16 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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.

Sounds like the problem is with the maybe_constant_init_1 unwrapping, it probably shouldn't strip INIT_EXPR if the type doesn't match that of 'decl'.

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.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/constexpr-prvalue1.C: New test.
---
  gcc/cp/constexpr.cc                           |  4 +++-
  .../g++.dg/cpp2a/constexpr-prvalue1.C         | 23 +++++++++++++++++++
  2 files changed, 26 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue1.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 59dd0668af3..204cda2a222 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3390,7 +3390,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
               current object under construction.  */
            if (!*non_constant_p && ctx->object
                && CLASS_TYPE_P (TREE_TYPE (res))
-               && !is_empty_class (TREE_TYPE (res)))
+               && !is_empty_class (TREE_TYPE (res))
+               && same_type_ignoring_top_level_qualifiers_p
+                   (TREE_TYPE (res), TREE_TYPE (ctx->object)))

If this happens, rather than just skip the replace_decl, I think we want to set *non_constant_p or I expect we'll end up with a wrong value somewhere.

Jason

Reply via email to