The following testcase is being miscompiled. This was extracted from the GCC EH newbies guide. // Testcase for proper handling of // c++ type, constructors and destructors. #include <stdio.h> int c, d; struct A { int i; A () { i = ++c; printf ("A() %d\n", i); } A (const A&) { i = ++c; printf ("A(const A&) %d\n", i); } ~A() { printf ("~A() %d\n", i); ++d; } }; void f() { printf ("Throwing 1...\n"); throw A(); } int main() { try { f(); } catch (A) { printf ("Caught.\n"); } printf ("c == %d, d == %d\n", c, d); return c != d; } You should get the following output: Throwing 1... A() 1 A(const A&) 2 ~A() 1 A(const A&) 3 Caught. ~A() 3 ~A() 2 c == 3, d == 3
As it turns out, the first bug is that the C++ front-end is producing a memberwise copy of the thrown object into the exception object: it is not invoking the copy constructor in "f()".
Some progress on this bug: * TARGET_EXPR's were not expanding into their destination if available correctly, causing extra copying to occur. This should not be a correctness problem, but is wasteful, and inefficient. This is now fixed. * The C++ front-end is eliding the first construct, copy ctor, and dtor calls, instead, just evaluating the ctor directly into the exception object. This is fine, and disablable with -fno-elide-constructors. FWIW, we are getting this output with -felide-constructors: Throwing 1... A() 1 ~A() 1 A(const A&) 2 ~A() 2 Caught. ~A() 2 ~A() 134523024 c == 2, d == 4 and this with -felid-constructors: Throwing 1... A() 1 A(const A&) 2 ~A() 2 ~A() 1 A(const A&) 3 ~A() 3 Caught. ~A() 3 ~A() 134523088 c == 3, d == 5 There is still a bug though, because c != d.
It turns out that the major part of this problem was not code-generating TARGET_EXPRs correctly. It seems that the cleanups should only be run if they are "orphaned", and we were running them always. This now brings the testcase to: Throwing 1... A() 1 A(const A&) 2 Caught. ~A() 2 ~A() 134522992 c == 2, d == 2 Which is almost exactly right (just s/134522992/1/)
Ok, the final piece of this puzzle was in the C++ EH runtime library, not passing the correct object pointer into the object destructor: http://mail.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20031006/007943.html This bug is now fixed.