[Bug c++/91369] Implement P0784R7: constexpr new

jakub at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Wed Jan 8 14:28:00 GMT 2020


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.


More information about the Gcc-bugs mailing list