https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369
--- Comment #30 from Jakub Jelinek <jakub at gcc dot gnu.org> --- (In reply to Toni Neubert from comment #28) > I have another test case which fails. (Maybe more..., I am sorry). No need to be sorry, your input is very valuable. Anyway, for the #c28 testcase (using struct S { constexpr S (int* i) : s{i} {} constexpr ~S () { delete s; } int *s; }; struct T { S t { new int }; }; constexpr auto foo () { T b; return true; } static_assert (foo ()); variant of it), not really sure if it is a compiler bug or testcase bug, the S class has defaulted copy ctor, so if it is ever copy constructed, there will be UB because you try to delete the same pointer multiple times. What I see happening is that in the T::T synthetized ctor, we have: <<cleanup_point <<< Unknown tree: expr_stmt (void) (((struct T *) this)->t = TARGET_EXPR <D.2161, <<< Unknown tree: aggr_init_expr 5 __ct_comp D.2161 (struct S *) <<< Unknown tree: void_cst >>> (int *) operator new (4) >>>>) >>>>>; and the TARGET_EXPR has as cleanup S::~S (&D.2161). So, when the constexpr evaluation evaluates this, it constructs the D.2161 temporary and queues a cleanup S::~S (&D.2161) until the CLEANUP_POINT_EXPR cleanup processing, then copies the value to the t member and when T::~T () is invoked during constexpr processing, S::~S (this->t) is invoked and that is the reason for the error, delete is called on the same pointer twice. Now, the reason why this doesn't fail when the foo function is invoked at runtime rather than at compile time is that cp_gimplify_init_expr has code to look through TARGET_EXPRs on the rhs of INIT_EXPR if their TARGET_EXPR_INITIAL is AGGR_INIT_EXPR/VEC_INIT_EXPR or COMPOUND_EXPR with those on the rightmost operand. The question is if what cp_gimplify_init_expr is just an optimization (then the testcase would be invalid), or if it is a mandatory C++ behavior, in that case I think cxx_eval_store_expression (if INIT_EXPR rather than MODIFY_EXPR) needs to detect this case and not sure if it can just look through the TARGET_EXPR (i.e. essentially ignore the cleanup), or if it needs to turn the whole INIT_EXPR into AGGR_INIT_EXPR or VEC_INIT_EXPR with different slot.