If an array element throws during destruction, undestructed elements in that array are not destructed. Other local variables are destructed. Clang calls destructors on all automatic objects, regardless whether in or out of an array. (And yes, I know throwing from destructors should be avoided, but that's hardly the point ;p) Relevant sections from standard ------------------------------- s15.2: As control passes from the point where an exception is thrown to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. ... An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects s1.8: A subobject can be ... an array element. Test case --------- #include <iostream> #include <exception> using namespace std; class A { public: A(int new_a) : a(new_a) { } ~A() noexcept(false) { cout << "a" << a <<".~A() "; if(std::uncaught_exception()) cout << "Unwinding"; cout << endl; if(a==4) throw a; } int a; }; int main() { try { A a1(1), a2(2); A arr[] = {3,4,5}; } catch(...) { } } Output (g++ 4.9.2) ------------------ a5.~A() a4.~A() a2.~A() Unwinding a1.~A() Unwinding Output (clang 3.5.0) -------------------- a5.~A() a4.~A() a3.~A() Unwinding a2.~A() Unwinding a1.~A() Unwinding
(In reply to Jonathan Dodd from comment #0) > If an array element throws during destruction, undestructed elements in that > array are not destructed. Other local variables are destructed. Clang calls > destructors on all automatic objects, regardless whether in or out of an > array. Not always ;-) https://llvm.org/bugs/show_bug.cgi?id=22877 This is probably related to PR66139
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:2fbc45486e13facfeb05bd6ddf70ff9973a30a3c commit r12-6331-g2fbc45486e13facfeb05bd6ddf70ff9973a30a3c Author: Jason Merrill <jason@redhat.com> Date: Wed Jan 5 09:49:37 2022 -0500 c++: keep destroying array after one dtor throws [PR66451] When we're cleaning up an array, if one destructor throws, we should still try to clean up the rest of the array. We can use TRY_CATCH_EXPR for this, instead of a TARGET_EXPR like my other recent patches, because a destructor call can't involve any temporaries that need to live longer. I thought about only doing this when we call build_vec_delete_1 from build_vec_init, but it seems appropriate for delete-expressions as well; we've said that the array's lifetime is over, it makes sense to keep trying to destroy it. The standard isn't clear, but clang seems to agree with me. PR c++/66451 gcc/cp/ChangeLog: * init.c (build_vec_delete_1): Handle throwing dtor. (build_vec_init): Tell it we're in a cleanup already. gcc/testsuite/ChangeLog: * g++.dg/eh/array3.C: New test. * g++.dg/eh/array1.C: Mark destructor as throw(). * g++.dg/ipa/devirt-40.C: Likewise. * g++.dg/warn/pr83054.C: Likewise. * g++.dg/eh/delete1.C: Shorten array to one element.
Fixed for GCC 12.