More exception handling improvements...  WIP.

Highlights include:

  Add a helper to generate __cxa_free_exception and _ZSt9terminatev.
  Add a region to handle EH object deallocation for ctor failures for throw.
  Add a terminate handler for __cxa_end_catch.
  A framework for adding cleanup actions for the exceptional edges only.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90305 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 420e275..85d02bb 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -31,9 +31,21 @@
   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
 }
 
+static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
+  // void __cxa_free_exception(void *thrown_exception);
+  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+  std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+  
+  const llvm::FunctionType *FTy = 
+  llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+                          Args, false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
+}
+
 static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
-  // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, 
-  //                   void (*dest) (void *) );
+  // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, 
+  //                  void (*dest) (void *));
 
   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
   std::vector<const llvm::Type*> Args(3, Int8PtrTy);
@@ -46,7 +58,7 @@
 }
 
 static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
-  // void __cxa_rethrow ();
+  // void __cxa_rethrow();
 
   const llvm::FunctionType *FTy = 
     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
@@ -55,7 +67,7 @@
 }
 
 static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
-  // void* __cxa_begin_catch ();
+  // void* __cxa_begin_catch();
 
   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@@ -67,7 +79,7 @@
 }
 
 static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
-  // void __cxa_end_catch ();
+  // void __cxa_end_catch();
 
   const llvm::FunctionType *FTy = 
     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
@@ -92,6 +104,15 @@
   return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
 }
 
+static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
+  // void __terminate();
+
+  const llvm::FunctionType *FTy = 
+    llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
+}
+
 // CopyObject - Utility to copy an object.  Calls copy constructor as necessary.
 // N is casted to the right type.
 static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
@@ -112,7 +133,19 @@
       CGF.EmitAggExpr(E, This, false);
     } else if (CXXConstructorDecl *CopyCtor
                = RD->getCopyConstructor(CGF.getContext(), 0)) {
-      // FIXME: region management
+      // All temporaries end before we call __cxa_throw
+      CodeGenFunction::CleanupScope TryScope(CGF);
+      {
+        // These actions are only on the exceptional edge.
+        CodeGenFunction::DelayedCleanupBlock Scope(CGF, true);
+
+        llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
+        const llvm::Type *Int8PtrTy
+          = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+        llvm::Value *ExceptionPtr = CGF.Builder.CreateBitCast(N, Int8PtrTy);
+        CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
+      }
+
       llvm::Value *Src = CGF.EmitLValue(E).getAddress();
 
       // Stolen from EmitClassAggrMemberwiseCopy
@@ -129,9 +162,8 @@
         CopyCtor->getType()->getAs<FunctionType>()->getResultType();
       CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
                    Callee, CallArgs, CopyCtor);
-      // FIXME: region management
     } else
-      CGF.ErrorUnsupported(E, "uncopyable object");
+      llvm::llvm_unreachable("uncopyable object");
   }
 }
 
@@ -154,7 +186,7 @@
       CGF.EmitAggregateCopy(This, E, ObjectType);
     } else if (CXXConstructorDecl *CopyCtor
                = RD->getCopyConstructor(CGF.getContext(), 0)) {
-      // FIXME: region management 
+      // FIXME: region management, call terminate
       llvm::Value *Src = E;
 
       // Stolen from EmitClassAggrMemberwiseCopy
@@ -241,16 +273,12 @@
 
   llvm::BasicBlock *PrevLandingPad = getInvokeDest();
   llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
-#if 0
   llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
-#endif
   llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
   llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
 
-#if 0
   // Push an EH context entry, used for handling rethrows.
   PushCleanupBlock(FinallyBlock);
-#endif
 
   // Emit the statements in the try {} block
   setInvokeDest(TryHandler);
@@ -306,6 +334,7 @@
   llvm::Value *Selector
     = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
                          SelectorArgs.end(), "selector");
+  llvm::BasicBlock *TerminateHandler = 0;
   for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
     const CXXCatchStmt *C = S.getHandler(i);
     VarDecl *CatchParam = C->getExceptionDecl();
@@ -375,13 +404,15 @@
 
     EmitBlock(MatchEnd);
 
-    // Unfortunately, we also have to generate another EH frame here
-    // in case this throws.
-    llvm::BasicBlock *MatchEndHandler =
-      createBasicBlock("match.end.handler");
-    llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont");
+    // Set up terminate handler
+    bool GenerateTerminate = false;
+    if (!TerminateHandler) {
+      TerminateHandler = createBasicBlock("terminate.handler");
+      GenerateTerminate = true;
+    }
+    llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
     Builder.CreateInvoke(getEndCatchFn(*this),
-                         Cont, MatchEndHandler,
+                         Cont, TerminateHandler,
                          Args.begin(), Args.begin());
 
     EmitBlock(Cont);
@@ -390,19 +421,31 @@
     if (Info.EndBlock)
       EmitBlock(Info.EndBlock);
 
-    EmitBlock(MatchEndHandler);
     Exc = Builder.CreateCall(llvm_eh_exception, "exc");
-    // We are required to emit this call to satisfy LLVM, even
-    // though we don't use the result.
-    Args.clear();
-    Args.push_back(Exc);
-    Args.push_back(Personality);
-    Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
-                                          0));
-    Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
     Builder.CreateStore(Exc, RethrowPtr);
     EmitBranchThroughCleanup(FinallyRethrow);
 
+    if (GenerateTerminate) {
+      GenerateTerminate = false;
+      EmitBlock(TerminateHandler);
+      Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+      // We are required to emit this call to satisfy LLVM, even
+      // though we don't use the result.
+      Args.clear();
+      Args.push_back(Exc);
+      Args.push_back(Personality);
+      Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+                                            0));
+      Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+      llvm::CallInst *TerminateCall = 
+        Builder.CreateCall(getTerminateFn(*this));
+      TerminateCall->setDoesNotReturn();
+      Builder.CreateUnreachable();
+
+      // Clear the insertion point to indicate we are in unreachable code.
+      Builder.ClearInsertionPoint();
+    }
+
     if (Next)
       EmitBlock(Next);
   }
@@ -413,7 +456,6 @@
 
   setInvokeDest(PrevLandingPad);
 
-#if 0
   EmitBlock(FinallyBlock);
 
   if (Info.SwitchBlock)
@@ -423,7 +465,6 @@
 
   // Branch around the rethrow code.
   EmitBranch(FinallyEnd);
-#endif
 
   EmitBlock(FinallyRethrow);
   Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),