[cfe-dev] [Bug] Destructor of temporary objects bound to reference variable not called in expected order.

Richard Smith richard at metafoo.co.uk
Sun Jul 6 21:08:10 PDT 2014


On Tue, Jul 1, 2014 at 2:22 AM, suyog sarda <sardask01 at gmail.com> wrote:

> Hi,
>
> This is a gcc test case
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> *extern "C" int printf (const char *, ...);int c;int r;struct A{   A() {
> printf ("A()\n"); if (c++) r = 1; }  A(const A&) { printf ("A(const
> A&)\n"); ++c; }  ~A() { printf ("~A()\n"); --c; }};struct B{  B(int, const
> A& = A()) { printf ("B()\n"); } };int main(){  B b[] = { 0, 1 };  return
> r;}*
>
> Output from Clang (latest trunk):
>
>
>
>
>
>
> *A()B()A()B()~A()~A()*
>
> Output from gcc 4.8 :
>
>
>
>
>
>
> *A() B()~A()A()B()~A() *
>
> As we can see, the destructor of temporary objects are not called
> immediately in case of clang.
> The temporary A passed to the constructor for b[0] should have been
> destroyed before going on to construct b[1].
>
> According to standards,
>
> The temporary to which the reference is bound or the temporary that is the
> complete object of a subobject to which the reference is bound persists for
> the lifetime of the reference except:
> — A temporary bound to a reference member in a constructor’s
> ctor-initializer ( 12.6.2) persists until the constructor exits.
> — A temporary bound to a reference parameter in a function call ( 5.2.2)
> persists until the completion of the full-expression containing the call.
>
> So even though A's temporary is bound to reference, it should get
> destroyed as soon as b[0] gets constructed before going forward to
> construct b[1].
>

We (incorrectly, per the C++ standard) treat top-level aggregate
initialization as a full-expression. However, I'm not entirely convinced
that this is a bug in Clang rather than a bug in the standard, especially
in C++11. As a demonstration of why this might be a standard defect:

typedef B BA[];

void f() {
  BA x = { 1, 2 }; // A(), B(), ~A(), A(), B(), ~A()
  auto &&y = BA { 1, 2 }; // A(), B(), A(), B(), ~A(), ~A()
} // ~B(), ~B(), ~B(), ~B()

This seems similar to http://llvm.org/bugs/show_bug.cgi?id=16476
>

It looks similar, but I think they're completely separate. That issue is
about end-of-scope cleanups and interleaving of lifetime-extended
temporaries with array elements. In this case, there is no
lifetime-extension.

Richard, any comment/help on this from you will be most welcomed (Since bug
> 16476 was filed by you :)). Does this require major change in code and
> handling of temporaries?
>

It would probably be straightforward to track where the full-expression
boundaries actually are during IR generation. As noted above, I'm not yet
convinced that Clang is the right place to fix this. =)


> Is this also related to
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1634 ?
>

Not in this instance, but there are nearby issues that are related (in
particular, destruction order if a temporary's destructor throws).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140706/c8190515/attachment.html>


More information about the cfe-dev mailing list