Bug 53868

Summary: Temporary for indirect binding is not destroyed when destructor from initializer temp throws
Product: gcc Reporter: Hubert Tong <hstong>
Component: c++Assignee: Jason Merrill <jason>
Status: RESOLVED FIXED    
Severity: normal CC: daniel.kruegler, jason, webrown.cpp
Priority: P3 Keywords: wrong-code
Version: 4.7.0   
Target Milestone: 12.0   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66139
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52320
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2022-01-06 00:00:00

Description Hubert Tong 2012-07-06 03:21:38 UTC
The temporary created for indirect binding should be completely constructed
(and from the output _it is_) before the destructors for temporaries in the
initializer are called.

In the following case, the destructor for a temporary in the initializer throws
an int. During stack unwinding, it seems the temporary bound to the reference
is missed.

### Self-contained source:> cat tempbindIndirect_inittempDtorThrows.cpp
extern "C" int printf(const char *, ...);
extern "C" void abort();

struct SubobjectInA {
   SubobjectInA();
   ~SubobjectInA();
};

struct A : SubobjectInA {
   A() = delete;
   A(const A &) = delete;
   A(A &&) { }
   A(int);
   ~A();
};

#define TRACE_FUNC( ... ) \
{   printf("%s\n", __PRETTY_FUNCTION__); __VA_ARGS__   }

struct Q {
   Q() : q(0)  TRACE_FUNC()
   ~Q();
   int q;
};

int main() {
   try { const A &a = Q().q; }
   catch (...) { return 0; }
   abort();
}

SubobjectInA::SubobjectInA()  TRACE_FUNC()
SubobjectInA::~SubobjectInA()  TRACE_FUNC()
A::A(int)  TRACE_FUNC()
A::~A()  TRACE_FUNC()
Q::~Q()  TRACE_FUNC( throw 0; )


### Compiler invocation:
g++-4.7.0 -std='c++11' tempbindIndirect_inittempDtorThrows.cpp -o test


### Compiler output:
(return code 0)


### Output from resulting executable:> ./test ; echo rc=$?
Q::Q()
SubobjectInA::SubobjectInA()
A::A(int)
Q::~Q()
rc=0


### Expected output:
Q::Q()
SubobjectInA::SubobjectInA()
A::A(int)
Q::~Q()
A::~A()
SubobjectInA::~SubobjectInA()
rc=0


### gcc -v output:> g++-4.7.0 -v
Using built-in specs.
COLLECT_GCC=g++-4.7.0
COLLECT_LTO_WRAPPER=/data/gcc/libexec/gcc/powerpc64-unknown-linux-gnu/4.7.0/lto-wrapper
Target: powerpc64-unknown-linux-gnu
Configured with: ../gcc-4.7.0/configure --prefix=/data/gcc --program-suffix=-4.7.0 --disable-libssp --disable-libgcj --enable-version-specific-runtime-libs --with-cpu=default32 --enable-secureplt --with-long-double-128 --enable-shared --enable-__cxa_atexit --enable-threads=posix --enable-languages=c,c++,fortran --with-mpfr=/usr/local/ --with-mpc=/usr/local/ --with-gmp=/usr/local/
Thread model: posix
gcc version 4.7.0 (GCC)
Comment 1 Jonathan Wakely 2012-07-06 08:17:16 UTC
(It doesn't matter for 4.7 but you need noexcept(false) on Q::~Q to use the testcase on trunk)
Comment 2 Andrew Pinski 2021-08-27 09:36:36 UTC
clang and GCC both produce the same result while ICC produces the bug reporter expected result.

This is also most likely related to PR 66139 and PR 52320.
Comment 3 GCC Commits 2022-01-07 00:26:02 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f

commit r12-6332-g4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jan 5 11:18:25 2022 -0500

    c++: clean up ref-extended temp on throwing dtor [PR53868]
    
    We have wrap_temporary_cleanups to handle the EH region nesting problems
    between cleanups for complete variables and cleanups for temporaries used in
    their construction, but we weren't calling it for temporaries extended from
    binding to a reference.
    
    We still don't want this for array cleanups (since my PR94041 fix), so I
    move that exception from initialize_local_var to wrap_temporary_cleanups.
    
            PR c++/53868
    
    gcc/cp/ChangeLog:
    
            * decl.c (cp_finish_decl): Use wrap_temporary_cleanups for
            cleanups from set_up_extended_ref_temp.
            (wrap_temporary_cleanups): Ignore array cleanups.
            (initialize_local_var): Don't check for array here.
            * cp-tree.h (BIND_EXPR_VEC_DTOR): New.
            * init.c (build_vec_delete_1): Set it.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/eh/ref-temp1.C: New test.
            * g++.dg/eh/ref-temp2.C: New test.
Comment 4 Jason Merrill 2022-01-28 04:34:18 UTC
Fixed for GCC 12.