[cfe-commits] r158488 - in /cfe/trunk: lib/CodeGen/CGException.cpp test/CodeGenCXX/exceptions.cpp

John McCall rjmccall at apple.com
Thu Jun 14 22:27:05 PDT 2012


Author: rjmccall
Date: Fri Jun 15 00:27:05 2012
New Revision: 158488

URL: http://llvm.org/viewvc/llvm-project?rev=158488&view=rev
Log:
It turns out that implementing the rethrow-on-fallthrough
semantics of a ctor/dtor function-try-block catch handler
by pushing a normal cleanup is not just overkill but actually
actively wrong when the handler contains an explicit return
(which is only legal in a dtor).  Just emit the rethrow as
ordinary code at the fallthrough point.  Fixes PR13102.

Modified:
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/test/CodeGenCXX/exceptions.cpp

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=158488&r1=158487&r2=158488&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Jun 15 00:27:05 2012
@@ -1127,14 +1127,6 @@
   CGF.EmitAutoVarCleanups(var);
 }
 
-namespace {
-  struct CallRethrow : EHScopeStack::Cleanup {
-    void Emit(CodeGenFunction &CGF, Flags flags) {
-      CGF.EmitCallOrInvoke(getReThrowFn(CGF));
-    }
-  };
-}
-
 /// Emit the structure of the dispatch block for the given catch scope.
 /// It is an invariant that the dispatch block already exists.
 static void emitCatchDispatchBlock(CodeGenFunction &CGF,
@@ -1246,11 +1238,12 @@
   if (HaveInsertPoint())
     Builder.CreateBr(ContBB);
 
-  // Determine if we need an implicit rethrow for all these catch handlers.
-  bool ImplicitRethrow = false;
+  // Determine if we need an implicit rethrow for all these catch handlers;
+  // see the comment below.
+  bool doImplicitRethrow = false;
   if (IsFnTryBlock)
-    ImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
-                      isa<CXXConstructorDecl>(CurCodeDecl);
+    doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
+                        isa<CXXConstructorDecl>(CurCodeDecl);
 
   // Perversely, we emit the handlers backwards precisely because we
   // want them to appear in source order.  In all of these cases, the
@@ -1273,15 +1266,24 @@
     // Initialize the catch variable and set up the cleanups.
     BeginCatch(*this, C);
 
-    // If there's an implicit rethrow, push a normal "cleanup" to call
-    // _cxa_rethrow.  This needs to happen before __cxa_end_catch is
-    // called, and so it is pushed after BeginCatch.
-    if (ImplicitRethrow)
-      EHStack.pushCleanup<CallRethrow>(NormalCleanup);
-
     // Perform the body of the catch.
     EmitStmt(C->getHandlerBlock());
 
+    // [except.handle]p11:
+    //   The currently handled exception is rethrown if control
+    //   reaches the end of a handler of the function-try-block of a
+    //   constructor or destructor.
+
+    // It is important that we only do this on fallthrough and not on
+    // return.  Note that it's illegal to put a return in a
+    // constructor function-try-block's catch handler (p14), so this
+    // really only applies to destructors.
+    if (doImplicitRethrow && HaveInsertPoint()) {
+      EmitCallOrInvoke(getReThrowFn(*this));
+      Builder.CreateUnreachable();
+      Builder.ClearInsertionPoint();
+    }
+
     // Fall out through the catch cleanups.
     CatchScope.ForceCleanup();
 

Modified: cfe/trunk/test/CodeGenCXX/exceptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/exceptions.cpp?rev=158488&r1=158487&r2=158488&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/exceptions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/exceptions.cpp Fri Jun 15 00:27:05 2012
@@ -414,3 +414,39 @@
   // CHECK: [[TEST9_NEW:%.*]] = call noalias i8* @_Znam
   // CHECK: call void @_ZdaPv(i8* [[TEST9_NEW]])
 }
+
+// In a destructor with a function-try-block, a return statement in a
+// catch handler behaves differently from running off the end of the
+// catch handler.  PR13102.
+namespace test10 {
+  extern void cleanup();
+  extern bool suppress;
+
+  struct A { ~A(); };
+  A::~A() try { cleanup(); } catch (...) { return; }
+  // CHECK:    define void @_ZN6test101AD1Ev(
+  // CHECK:      invoke void @_ZN6test107cleanupEv()
+  // CHECK-NOT:  rethrow
+  // CHECK:      ret void
+
+  struct B { ~B(); };
+  B::~B() try { cleanup(); } catch (...) {}
+  // CHECK:    define void @_ZN6test101BD1Ev(
+  // CHECK:      invoke void @_ZN6test107cleanupEv()
+  // CHECK:      call i8* @__cxa_begin_catch
+  // CHECK-NEXT: invoke void @__cxa_rethrow()
+  // CHECK:      unreachable
+
+  struct C { ~C(); };
+  C::~C() try { cleanup(); } catch (...) { if (suppress) return; }
+  // CHECK:    define void @_ZN6test101CD1Ev(
+  // CHECK:      invoke void @_ZN6test107cleanupEv()
+  // CHECK:      call i8* @__cxa_begin_catch
+  // CHECK-NEXT: load i8* @_ZN6test108suppressE, align 1
+  // CHECK-NEXT: trunc
+  // CHECK-NEXT: br i1
+  // CHECK:      call void @__cxa_end_catch()
+  // CHECK-NEXT: br label
+  // CHECK:      invoke void @__cxa_rethrow()
+  // CHECK:      unreachable
+}





More information about the cfe-commits mailing list