[cfe-commits] r127980 - in /cfe/trunk/lib: CodeGen/CGException.cpp CodeGen/CGException.h CodeGen/CGObjCGNU.cpp CodeGen/CGRTTI.cpp Sema/SemaDeclCXX.cpp

Douglas Gregor dgregor at apple.com
Mon Mar 21 10:30:20 PDT 2011


Bill, please merge this into the 2.9 branch!

	Thanks,
	Doug

On Mar 20, 2011, at 10:35 PM, David Chisnall wrote:

> Author: theraven
> Date: Sun Mar 20 16:35:39 2011
> New Revision: 127980
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=127980&view=rev
> Log:
> Fix Objective-C++ exceptions (GNU runtime).
> 
> 
> Modified:
>    cfe/trunk/lib/CodeGen/CGException.cpp
>    cfe/trunk/lib/CodeGen/CGException.h
>    cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
>    cfe/trunk/lib/CodeGen/CGRTTI.cpp
>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> 
> Modified: cfe/trunk/lib/CodeGen/CGException.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=127980&r1=127979&r2=127980&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGException.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGException.cpp Sun Mar 20 16:35:39 2011
> @@ -160,6 +160,7 @@
> const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0");
> const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0",
>                                             "objc_exception_throw");
> +const EHPersonality EHPersonality::GNU_ObjCXX("__gnustep_objcxx_personality_v0");
> 
> static const EHPersonality &getCPersonality(const LangOptions &L) {
>   if (L.SjLjExceptions)
> @@ -201,7 +202,7 @@
> 
>   // The GNU runtime's personality function inherently doesn't support
>   // mixed EH.  Use the C++ personality just to avoid returning null.
> -  return getCXXPersonality(L);
> +  return EHPersonality::GNU_ObjCXX;
> }
> 
> const EHPersonality &EHPersonality::get(const LangOptions &L) {
> 
> Modified: cfe/trunk/lib/CodeGen/CGException.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.h?rev=127980&r1=127979&r2=127980&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGException.h (original)
> +++ cfe/trunk/lib/CodeGen/CGException.h Sun Mar 20 16:35:39 2011
> @@ -41,6 +41,7 @@
>   static const EHPersonality GNU_C;
>   static const EHPersonality GNU_C_SJLJ;
>   static const EHPersonality GNU_ObjC;
> +  static const EHPersonality GNU_ObjCXX;
>   static const EHPersonality NeXT_ObjC;
>   static const EHPersonality GNU_CPlusPlus;
>   static const EHPersonality GNU_CPlusPlus_SJLJ;
> 
> Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=127980&r1=127979&r2=127980&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Sun Mar 20 16:35:39 2011
> @@ -30,6 +30,7 @@
> #include "llvm/LLVMContext.h"
> #include "llvm/ADT/SmallVector.h"
> #include "llvm/ADT/StringMap.h"
> +#include "llvm/Support/CallSite.h"
> #include "llvm/Support/Compiler.h"
> #include "llvm/Target/TargetData.h"
> 
> @@ -141,6 +142,7 @@
>     if (V->getType() == Ty) return V;
>     return B.CreateBitCast(V, Ty);
>   }
> +  void EmitObjCXXTryStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtTryStmt &S);
> public:
>   CGObjCGNU(CodeGen::CodeGenModule &cgm);
>   virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
> @@ -416,8 +418,62 @@
> }
> 
> llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
> -  llvm_unreachable("asking for catch type for ObjC type in GNU runtime");
> -  return 0;
> +  // For Objective-C++, we want to provide the ability to catch both C++ and
> +  // Objective-C objects in the same function.
> +
> +  // There's a particular fixed type info for 'id'.
> +  if (T->isObjCIdType() ||
> +      T->isObjCQualifiedIdType()) {
> +    llvm::Constant *IDEHType =
> +      CGM.getModule().getGlobalVariable("__objc_id_type_info");
> +    if (!IDEHType)
> +      IDEHType =
> +        new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty,
> +                                 false,
> +                                 llvm::GlobalValue::ExternalLinkage,
> +                                 0, "__objc_id_type_info");
> +    return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty);
> +  }
> +
> +  const ObjCObjectPointerType *PT =
> +    T->getAs<ObjCObjectPointerType>();
> +  assert(PT && "Invalid @catch type.");
> +  const ObjCInterfaceType *IT = PT->getInterfaceType();
> +  assert(IT && "Invalid @catch type.");
> +  std::string className = IT->getDecl()->getIdentifier()->getName();
> +
> +  std::string typeinfoName = "__objc_eh_typeinfo_" + className;
> +
> +  // Return the existing typeinfo if it exists
> +  llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName);
> +  if (typeinfo) return typeinfo;
> +
> +  // Otherwise create it.
> +
> +  // vtable for gnustep::libobjc::__objc_class_type_info
> +  // It's quite ugly hard-coding this.  Ideally we'd generate it using the host
> +  // platform's name mangling.
> +  const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE";
> +  llvm::Constant *Vtable = TheModule.getGlobalVariable(vtableName);
> +  if (!Vtable) {
> +    Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true,
> +            llvm::GlobalValue::ExternalLinkage, 0, vtableName);
> +  }
> +  llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2);
> +  Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, &Two, 1);
> +  Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty);
> +
> +  llvm::Constant *typeName =
> +    ExportUniqueString(className, "__objc_eh_typename_");
> +
> +  std::vector<llvm::Constant*> fields;
> +  fields.push_back(Vtable);
> +  fields.push_back(typeName);
> +  llvm::Constant *TI = 
> +      MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
> +              NULL), fields, "__objc_eh_typeinfo_" + className,
> +          llvm::GlobalValue::LinkOnceODRLinkage);
> +  return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty);
> }
> 
> llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str,
> @@ -1945,6 +2001,138 @@
>     llvm::BasicBlock *Block;
>     llvm::Value *TypeInfo;
>   };
> +
> +  struct CallObjCEndCatch : EHScopeStack::Cleanup {
> +    CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) :
> +      MightThrow(MightThrow), Fn(Fn) {}
> +    bool MightThrow;
> +    llvm::Value *Fn;
> +
> +    void Emit(CodeGenFunction &CGF, bool IsForEH) {
> +      if (!MightThrow) {
> +        CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
> +        return;
> +      }
> +
> +      CGF.EmitCallOrInvoke(Fn, 0, 0);
> +    }
> +  };
> +}
> +
> +void CGObjCGNU::EmitObjCXXTryStmt(CodeGen::CodeGenFunction &CGF,
> +                                  const ObjCAtTryStmt &S) {
> +  std::vector<const llvm::Type*> Args(1, PtrToInt8Ty);
> +  llvm::FunctionType *FTy = llvm::FunctionType::get(PtrToInt8Ty, Args, false);
> +  const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
> +
> +  llvm::Constant *beginCatchFn =
> +    CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
> +
> +  FTy = llvm::FunctionType::get(VoidTy, false);
> +  llvm::Constant *endCatchFn =
> +    CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
> +  FTy = llvm::FunctionType::get(VoidTy, Args, false);
> +  llvm::Constant *exceptionRethrowFn =
> +    CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
> +
> +  // Jump destination for falling out of catch bodies.
> +  CodeGenFunction::JumpDest Cont;
> +  if (S.getNumCatchStmts())
> +    Cont = CGF.getJumpDestInCurrentScope("eh.cont");
> +
> +  CodeGenFunction::FinallyInfo FinallyInfo;
> +  if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
> +    FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(),
> +                                        beginCatchFn,
> +                                        endCatchFn,
> +                                        exceptionRethrowFn);
> +
> +  llvm::SmallVector<CatchHandler, 8> Handlers;
> +
> +  // Enter the catch, if there is one.
> +  if (S.getNumCatchStmts()) {
> +    for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
> +      const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I);
> +      const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
> +
> +      Handlers.push_back(CatchHandler());
> +      CatchHandler &Handler = Handlers.back();
> +      Handler.Variable = CatchDecl;
> +      Handler.Body = CatchStmt->getCatchBody();
> +      Handler.Block = CGF.createBasicBlock("catch");
> +
> +      // @catch(...) always matches.
> +      if (!CatchDecl) {
> +        Handler.TypeInfo = 0; // catch-all
> +        // Don't consider any other catches.
> +        break;
> +      }
> +
> +      Handler.TypeInfo = GetEHType(CatchDecl->getType());
> +    }
> +
> +    EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
> +    for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
> +      Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block);
> +  }
> +  
> +  // Emit the try body.
> +  CGF.EmitStmt(S.getTryBody());
> +
> +  // Leave the try.
> +  if (S.getNumCatchStmts())
> +    CGF.EHStack.popCatch();
> +
> +  // Remember where we were.
> +  CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
> +
> +  // Emit the handlers.
> +  for (unsigned I = 0, E = Handlers.size(); I != E; ++I) {
> +    CatchHandler &Handler = Handlers[I];
> +
> +    CGF.EmitBlock(Handler.Block);
> +    llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
> +
> +    // Enter the catch.
> +    llvm::CallInst *Exn =
> +      CGF.Builder.CreateCall(beginCatchFn, RawExn,
> +                             "exn.adjusted");
> +    Exn->setDoesNotThrow();
> +
> +    // Add a cleanup to leave the catch.
> +    bool EndCatchMightThrow = (Handler.Variable == 0);
> +    CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
> +                                              EndCatchMightThrow,
> +                                              endCatchFn);
> +
> +    // Bind the catch parameter if it exists.
> +    if (const VarDecl *CatchParam = Handler.Variable) {
> +      const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
> +      llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
> +
> +      CGF.EmitAutoVarDecl(*CatchParam);
> +      CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam));
> +    }
> +
> +    CGF.ObjCEHValueStack.push_back(Exn);
> +    CGF.EmitStmt(Handler.Body);
> +    CGF.ObjCEHValueStack.pop_back();
> +
> +    // Leave the earlier cleanup.
> +    CGF.PopCleanupBlock();
> +
> +    CGF.EmitBranchThroughCleanup(Cont);
> +  }  
> +
> +  // Go back to the try-statement fallthrough.
> +  CGF.Builder.restoreIP(SavedIP);
> +
> +  // Pop out of the normal cleanup on the finally.
> +  if (S.getFinallyStmt())
> +    CGF.ExitFinallyBlock(FinallyInfo);
> +
> +  if (Cont.isValid())
> +    CGF.EmitBlock(Cont.getBlock());
> }
> 
> void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
> @@ -1958,6 +2146,13 @@
>   // (or even _Unwind_DeleteException), but probably doesn't
>   // interoperate very well with foreign exceptions.
> 
> +  // In Objective-C++ mode, we actually emit something equivalent to the C++
> +  // exception handler.
> +  if (CGM.getLangOptions().CPlusPlus) {
> +    EmitObjCXXTryStmt(CGF, S);
> +    return;
> +  }
> +
>   // Jump destination for falling out of catch bodies.
>   CodeGenFunction::JumpDest Cont;
>   if (S.getNumCatchStmts())
> 
> Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=127980&r1=127979&r2=127980&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sun Mar 20 16:35:39 2011
> @@ -16,6 +16,7 @@
> #include "clang/AST/RecordLayout.h"
> #include "clang/AST/Type.h"
> #include "clang/Frontend/CodeGenOptions.h"
> +#include "CGObjCRuntime.h"
> 
> using namespace clang;
> using namespace CodeGen;
> @@ -977,6 +978,10 @@
>     const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
>     return llvm::Constant::getNullValue(Int8PtrTy);
>   }
> +  
> +  if (ForEH && Ty->isObjCObjectPointerType() && !Features.NeXTRuntime) {
> +    return Runtime->GetEHType(Ty);
> +  }
> 
>   return RTTIBuilder(*this).BuildTypeInfo(Ty);
> }
> 
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=127980&r1=127979&r2=127980&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Mar 20 16:35:39 2011
> @@ -6775,10 +6775,7 @@
>       Diag(Loc, diag::err_objc_object_catch);
>       Invalid = true;
>     } else if (T->isObjCObjectPointerType()) {
> -      if (!getLangOptions().NeXTRuntime) {
> -        Diag(Loc, diag::err_objc_pointer_cxx_catch_gnu);
> -        Invalid = true;
> -      } else if (!getLangOptions().ObjCNonFragileABI) {
> +      if (!getLangOptions().ObjCNonFragileABI) {
>         Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile);
>         Invalid = true;
>       }
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits





More information about the cfe-commits mailing list