The following example has constructors of class A called 4 times but destructors only 3 times. Apparently, if an exception is thrown during the construction of an aggregate class, the destructors of already constructed data members are not called. #include <iostream> #define FUNCTION_NAME __PRETTY_FUNCTION__ #define TRACE_FUNCTION { std::cout << this << "->" << FUNCTION_NAME << std::endl; } struct A { A() { TRACE_FUNCTION; } A(int) { TRACE_FUNCTION; } A(const A&) { TRACE_FUNCTION; } A &operator=(const A&) TRACE_FUNCTION; ~A() TRACE_FUNCTION; }; int main() { try { struct X { A e1[2], e2; } x2[3] = { 1, 2, 3, 4, (0, throw 9, 5), 6 }; } catch (...) { } } Detailed version information: Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-cygwin/4.5.3/lto-wrapper.exe Target: i686-pc-cygwin Configured with: /gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3/configure --srcdir=/gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/lib --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --datarootdir=/usr/share --docdir=/usr/share/doc/gcc4 -C --datadir=/usr/share --infodir=/usr/share/info --mandir=/usr/share/man -v --with-gmp=/usr --with-mpfr=/usr --enable-bootstrap --enable-version-specific-runtime-libs --libexecdir=/usr/lib --enable-static --enable-shared --enable-shared-libgcc --disable-__cxa_atexit --with-gnu-ld --with-gnu-as --with-dwarf2 --disable-sjlj-exceptions --enable-languages=ada,c,c++,fortran,java,lto,objc,obj-c++ --enable-graphite --enable-lto --enable-java-awt=gtk --disable-symvers --enable-libjava --program-suffix=-4 --enable-libgomp --enable-libssp --enable-libada --enable-threads=posix --with-arch=i686 --with-tune=generic --enable-libgcj-sublibs CC=gcc-4 CXX=g++-4 CC_FOR_TARGET=gcc-4 CXX_FOR_TARGET=g++-4 GNATMAKE_FOR_TARGET=gnatmake GNATBIND_FOR_TARGET=gnatbind --with-ecj-jar=/usr/share/java/ecj.jar Thread model: posix gcc version 4.5.3 (GCC)
Confirmed for 4.7.0 20120218 (experimental). Reduced example with added information: //---- #include <iostream> #define FUNCTION_NAME __PRETTY_FUNCTION__ #define TRACE_FUNCTION(I) { std::cout << this << "->" << FUNCTION_NAME << "; i = " << I << std::endl; } struct A { int i; A(int i) : i(i) { TRACE_FUNCTION(i); } A(const A& rhs) : i(rhs.i) { TRACE_FUNCTION(i); } A &operator=(const A& rhs) { i = rhs.i; TRACE_FUNCTION(i); return *this; } ~A() { TRACE_FUNCTION(i); } }; struct Y { A e1[2]; }; int main() { try { Y y1[1] = { {{1, (throw 0, 2)} } }; } catch (int) { } } //---- Observed output is: 0x22fd60->A::A(int); i = 1 It does not happen when the local array y1 is replaced by a non-array Y.
This looks similar to PR 41449 which Jason fixed
(In reply to comment #2) Agreed. It seems that the fix did not solve some array-related corner cases like this one.
(In reply to Daniel Krügler from comment #1) > Confirmed for 4.7.0 20120218 (experimental). > (In reply to Daniel Krügler from comment #3) > (In reply to comment #2) > > Agreed. It seems that the fix did not solve some array-related corner cases > like this one. Changing status to NEW then.
Related to PR 57510
Author: jason Date: Thu Dec 19 14:07:22 2019 New Revision: 279577 URL: https://gcc.gnu.org/viewcvs?rev=279577&root=gcc&view=rev Log: PR c++/52320 - EH cleanups for partially constructed arrays. This testcase wasn't fixed by the 66139 patch; split_nonconstant_init_1 was failing to add a cleanup for an array member of a class (e.g. e1) that will run if initializing a later member (e.g. e2) throws. * typeck2.c (split_nonconstant_init_1): Add nested parm. Add cleanup for whole array if true. Added: trunk/gcc/testsuite/g++.dg/eh/aggregate1.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/typeck2.c
Fixed for GCC 10 so far.
commit r10-7110-g14af5d9b19b0f4ee1d929e505e245ae5c2f6bdc6 Author: Jason Merrill <jason@redhat.com> Date: Tue Mar 10 16:05:18 2020 -0400 c++: Partially revert patch for PR66139. The patch for 66139 exposed a long-standing bug with split_nonconstant_init (since 4.7, apparently): initializion of individual elements of an aggregate are not a full-expressions, but split_nonconstant_init was making full-expressions out of them. My fix for 66139 extended the use of split_nonconstant_init, and thus the bug, to aggregate initialization of temporaries within an expression, in which context (PR94041) the bug is more noticeable. PR93922 is a problem with my implementation strategy of splitting out at gimplification time, introducing function calls that weren't in the GENERIC. So I'm going to revert the patch now and try again for GCC 11. gcc/cp/ChangeLog 2020-03-10 Jason Merrill <jason@redhat.com> PR c++/93922 PR c++/94041 PR c++/52320 PR c++/66139 * cp-gimplify.c (cp_gimplify_init_expr): Partially revert patch for 66139: Don't split_nonconstant_init. Remove pre_p parameter.
GCC 10.1 has been released.
GCC 10.2 is released, adjusting target milestone.
GCC 10.3 is being released, retargeting bugs to GCC 10.4.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:4f6bc28fc7dd86bd9e7408cbf28de1e973dd1eda commit r12-6329-g4f6bc28fc7dd86bd9e7408cbf28de1e973dd1eda Author: Jason Merrill <jason@redhat.com> Date: Thu Mar 5 15:50:45 2020 -0500 c++: EH and partially constructed aggr temp [PR66139] Now that PR94041 is fixed, I can return to addressing PR66139, missing cleanups for partially constructed aggregate temporaries. My previous approach of calling split_nonconstant_init in cp_gimplify_init_expr broke because gimplification is too late to be introducing destructor calls. So instead I now call it under cp_fold_function, just before cp_genericize; doing it from cp_genericize itself ran into trouble with the rewriting of invisible references. So now the prediction in cp_gimplify_expr that cp_gimplify_init_expr might need to replace references to TARGET_EXPR_SLOT within TARGET_EXPR_INITIAL has come to pass. constexpr.c already had the simple search-and-replace tree walk I needed, but it needed to be fixed to actually replace all occurrences instead of just the first one. Handling of VEC_INIT_EXPR at gimplify time had similar issues that we worked around with build_vec_init_elt, so I'm moving that to cp_fold_function as well. But it seems that build_vec_init_elt is still useful for setting the VEC_INIT_EXPR_IS_CONSTEXPR flag, so I'm leaving it alone. This also fixes 52320, because build_aggr_init of each X from build_vec_init builds an INIT_EXPR rather than call split_nonconstant_init at that point, and now that INIT_EXPR gets split later. PR c++/66139 PR c++/52320 gcc/cp/ChangeLog: * constexpr.c (replace_decl): Rename from replace_result_decl. * cp-tree.h (replace_decl): Declare it. * cp-gimplify.c (cp_gimplify_init_expr): Call it. (cp_gimplify_expr): Don't handle VEC_INIT_EXPR. (cp_genericize_init, cp_genericize_init_expr) (cp_genericize_target_expr): New. (cp_fold_r): Call them. * tree.c (build_array_copy): Add a TARGET_EXPR. * typeck2.c (digest_init_r): Look through a TARGET_EXPR. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/initlist116.C: New test. * g++.dg/cpp0x/initlist117.C: New test. * g++.dg/cpp0x/lambda/lambda-eh.C: New test. * g++.dg/eh/aggregate1.C: New test.
Fixed for GCC 12.