Index: cfe/trunk/include/clang/AST/Mangle.h =================================================================== --- cfe/trunk/include/clang/AST/Mangle.h +++ cfe/trunk/include/clang/AST/Mangle.h @@ -197,6 +197,15 @@ virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, raw_ostream &) = 0; + virtual void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile, + uint32_t NumEntries, raw_ostream &Out) = 0; + + virtual void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries, + raw_ostream &Out) = 0; + + virtual void mangleCXXCatchableType(QualType T, uint32_t Size, + raw_ostream &Out) = 0; + virtual void mangleCXXRTTIBaseClassDescriptor( const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) = 0; Index: cfe/trunk/lib/AST/MicrosoftMangle.cpp =================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp @@ -110,6 +110,12 @@ void mangleCXXVBTable(const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) override; + void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile, + uint32_t NumEntries, raw_ostream &Out) override; + void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries, + raw_ostream &Out) override; + void mangleCXXCatchableType(QualType T, uint32_t Size, + raw_ostream &Out) override; void mangleCXXRTTI(QualType T, raw_ostream &Out) override; void mangleCXXRTTIName(QualType T, raw_ostream &Out) override; void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived, @@ -2278,6 +2284,39 @@ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); } +void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T, + bool IsConst, + bool IsVolatile, + uint32_t NumEntries, + raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_TI"; + if (IsConst) + Mangler.getStream() << 'C'; + if (IsVolatile) + Mangler.getStream() << 'V'; + Mangler.getStream() << NumEntries; + Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); +} + +void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray( + QualType T, uint32_t NumEntries, raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_CTA"; + Mangler.getStream() << NumEntries; + Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); +} + +void MicrosoftMangleContextImpl::mangleCXXCatchableType(QualType T, + uint32_t Size, + raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_CT??_R0"; + Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); + Mangler.getStream() << "@8"; + Mangler.getStream() << Size; +} + void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor( const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) { Index: cfe/trunk/lib/CodeGen/CGCXXABI.h =================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.h +++ cfe/trunk/lib/CodeGen/CGCXXABI.h @@ -215,6 +215,7 @@ llvm::Value *Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) = 0; virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0; + virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0; virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0; Index: cfe/trunk/lib/CodeGen/CGException.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGException.cpp +++ cfe/trunk/lib/CodeGen/CGException.cpp @@ -25,15 +25,6 @@ using namespace clang; using namespace CodeGen; -static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) { - // void *__cxa_allocate_exception(size_t thrown_size); - - llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false); - - return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); -} - static llvm::Constant *getFreeExceptionFn(CodeGenModule &CGM) { // void __cxa_free_exception(void *thrown_exception); @@ -43,17 +34,6 @@ return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); } -static llvm::Constant *getThrowFn(CodeGenModule &CGM) { - // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, - // void (*dest) (void *)); - - llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy }; - llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false); - - return CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); -} - static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) { // void __cxa_call_unexpected(void *thrown_exception); @@ -381,17 +361,16 @@ // differs from EmitAnyExprToMem only in that, if a final copy-ctor // call is required, an exception within that copy ctor causes // std::terminate to be invoked. -static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e, - llvm::Value *addr) { +void CodeGenFunction::EmitAnyExprToExn(const Expr *e, llvm::Value *addr) { // Make sure the exception object is cleaned up if there's an // exception during initialization. - CGF.pushFullExprCleanup(EHCleanup, addr); - EHScopeStack::stable_iterator cleanup = CGF.EHStack.stable_begin(); + pushFullExprCleanup(EHCleanup, addr); + EHScopeStack::stable_iterator cleanup = EHStack.stable_begin(); // __cxa_allocate_exception returns a void*; we need to cast this // to the appropriate type for the object. - llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo(); - llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, ty); + llvm::Type *ty = ConvertTypeForMem(e->getType())->getPointerTo(); + llvm::Value *typedAddr = Builder.CreateBitCast(addr, ty); // FIXME: this isn't quite right! If there's a final unelided call // to a copy constructor, then according to [except.terminate]p1 we @@ -400,11 +379,11 @@ // evaluated but before the exception is caught. But the best way // to handle that is to teach EmitAggExpr to do the final copy // differently if it can't be elided. - CGF.EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(), - /*IsInit*/ true); + EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(), + /*IsInit*/ true); // Deactivate the cleanup block. - CGF.DeactivateCleanupBlock(cleanup, cast(typedAddr)); + DeactivateCleanupBlock(cleanup, cast(typedAddr)); } llvm::Value *CodeGenFunction::getExceptionSlot() { @@ -436,75 +415,18 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint) { - if (!E->getSubExpr()) { - CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/true); - - // throw is an expression, and the expression emitters expect us - // to leave ourselves at a valid insertion point. - if (KeepInsertionPoint) - EmitBlock(createBasicBlock("throw.cont")); - - return; - } - - if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) { - // Call std::terminate(). - llvm::CallInst *TermCall = EmitNounwindRuntimeCall(CGM.getTerminateFn()); - TermCall->setDoesNotReturn(); - - // throw is an expression, and the expression emitters expect us - // to leave ourselves at a valid insertion point. - if (KeepInsertionPoint) - EmitBlock(createBasicBlock("throw.cont")); - - return; - } - - QualType ThrowType = E->getSubExpr()->getType(); - - if (ThrowType->isObjCObjectPointerType()) { - const Stmt *ThrowStmt = E->getSubExpr(); - const ObjCAtThrowStmt S(E->getExprLoc(), - const_cast(ThrowStmt)); - CGM.getObjCRuntime().EmitThrowStmt(*this, S, false); - // This will clear insertion point which was not cleared in - // call to EmitThrowStmt. - if (KeepInsertionPoint) - EmitBlock(createBasicBlock("throw.cont")); - return; - } - - // Now allocate the exception object. - llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity(); - - llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM); - llvm::CallInst *ExceptionPtr = - EmitNounwindRuntimeCall(AllocExceptionFn, - llvm::ConstantInt::get(SizeTy, TypeSize), - "exception"); - - EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr); - - // Now throw the exception. - llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, - /*ForEH=*/true); - - // The address of the destructor. If the exception type has a - // trivial destructor (or isn't a record), we just pass null. - llvm::Constant *Dtor = nullptr; - if (const RecordType *RecordTy = ThrowType->getAs()) { - CXXRecordDecl *Record = cast(RecordTy->getDecl()); - if (!Record->hasTrivialDestructor()) { - CXXDestructorDecl *DtorD = Record->getDestructor(); - Dtor = CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete); - Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy); + if (const Expr *SubExpr = E->getSubExpr()) { + QualType ThrowType = SubExpr->getType(); + if (ThrowType->isObjCObjectPointerType()) { + const Stmt *ThrowStmt = E->getSubExpr(); + const ObjCAtThrowStmt S(E->getExprLoc(), const_cast(ThrowStmt)); + CGM.getObjCRuntime().EmitThrowStmt(*this, S, false); + } else { + CGM.getCXXABI().emitThrow(*this, E); } + } else { + CGM.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true); } - if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy); - - llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor }; - EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args); // throw is an expression, and the expression emitters expect us // to leave ourselves at a valid insertion point. Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -1567,6 +1567,8 @@ void EmitAnyExprToMem(const Expr *E, llvm::Value *Location, Qualifiers Quals, bool IsInitializer); + void EmitAnyExprToExn(const Expr *E, llvm::Value *Addr); + /// EmitExprAsInit - Emits the code necessary to initialize a /// location in memory with the given initializer. void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue, Index: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp @@ -115,6 +115,7 @@ const CXXDestructorDecl *Dtor) override; void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override; + void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override; void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override; @@ -916,6 +917,59 @@ CGF.EmitRuntimeCallOrInvoke(Fn); } +static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) { + // void *__cxa_allocate_exception(size_t thrown_size); + + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false); + + return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); +} + +static llvm::Constant *getThrowFn(CodeGenModule &CGM) { + // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, + // void (*dest) (void *)); + + llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy }; + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false); + + return CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); +} + +void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { + QualType ThrowType = E->getSubExpr()->getType(); + // Now allocate the exception object. + llvm::Type *SizeTy = CGF.ConvertType(getContext().getSizeType()); + uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity(); + + llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM); + llvm::CallInst *ExceptionPtr = CGF.EmitNounwindRuntimeCall( + AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); + + CGF.EmitAnyExprToExn(E->getSubExpr(), ExceptionPtr); + + // Now throw the exception. + llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, + /*ForEH=*/true); + + // The address of the destructor. If the exception type has a + // trivial destructor (or isn't a record), we just pass null. + llvm::Constant *Dtor = nullptr; + if (const RecordType *RecordTy = ThrowType->getAs()) { + CXXRecordDecl *Record = cast(RecordTy->getDecl()); + if (!Record->hasTrivialDestructor()) { + CXXDestructorDecl *DtorD = Record->getDestructor(); + Dtor = CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete); + Dtor = llvm::ConstantExpr::getBitCast(Dtor, CGM.Int8PtrTy); + } + } + if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy); + + llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor }; + CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args); +} + static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) { // void *__dynamic_cast(const void *sub, // const abi::__class_type_info *src, Index: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp @@ -43,7 +43,8 @@ MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM), BaseClassDescriptorType(nullptr), ClassHierarchyDescriptorType(nullptr), - CompleteObjectLocatorType(nullptr) {} + CompleteObjectLocatorType(nullptr), CatchableTypeType(nullptr), + ThrowInfoType(nullptr) {} bool HasThisReturn(GlobalDecl GD) const override; bool hasMostDerivedReturn(GlobalDecl GD) const override; @@ -74,6 +75,7 @@ const CXXDestructorDecl *Dtor) override; void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override; + void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override; void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override; @@ -415,6 +417,9 @@ if (!isImageRelative()) return PtrVal; + if (PtrVal->isNullValue()) + return llvm::Constant::getNullValue(CGM.IntTy); + llvm::Constant *ImageBaseAsInt = llvm::ConstantExpr::getPtrToInt(getImageBase(), CGM.IntPtrTy); llvm::Constant *PtrValAsInt = @@ -565,6 +570,79 @@ void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override; + llvm::StructType *getCatchableTypeType() { + if (CatchableTypeType) + return CatchableTypeType; + llvm::Type *FieldTypes[] = { + CGM.IntTy, // Flags + getImageRelativeType(CGM.Int8PtrTy), // TypeDescriptor + CGM.IntTy, // NonVirtualAdjustment + CGM.IntTy, // OffsetToVBPtr + CGM.IntTy, // VBTableIndex + CGM.IntTy, // Size + getImageRelativeType(CGM.Int8PtrTy) // CopyCtor + }; + CatchableTypeType = llvm::StructType::create( + CGM.getLLVMContext(), FieldTypes, "eh.CatchableType"); + return CatchableTypeType; + } + + llvm::StructType *getCatchableTypeArrayType(uint32_t NumEntries) { + llvm::StructType *&CatchableTypeArrayType = + CatchableTypeArrayTypeMap[NumEntries]; + if (CatchableTypeArrayType) + return CatchableTypeArrayType; + + llvm::SmallString<23> CTATypeName("eh.CatchableTypeArray."); + CTATypeName += llvm::utostr(NumEntries); + llvm::Type *CTType = + getImageRelativeType(getCatchableTypeType()->getPointerTo()); + llvm::Type *FieldTypes[] = { + CGM.IntTy, // NumEntries + llvm::ArrayType::get(CTType, NumEntries) // CatchableTypes + }; + CatchableTypeArrayType = + llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, CTATypeName); + return CatchableTypeArrayType; + } + + llvm::StructType *getThrowInfoType() { + if (ThrowInfoType) + return ThrowInfoType; + llvm::Type *FieldTypes[] = { + CGM.IntTy, // Flags + getImageRelativeType(CGM.Int8PtrTy), // CleanupFn + getImageRelativeType(CGM.Int8PtrTy), // ForwardCompat + getImageRelativeType(CGM.Int8PtrTy) // CatchableTypeArray + }; + ThrowInfoType = llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, + "eh.ThrowInfo"); + return ThrowInfoType; + } + + llvm::Constant *getThrowFn() { + // _CxxThrowException is passed an exception object and a ThrowInfo object + // which describes the exception. + llvm::Type *Args[] = {CGM.Int8PtrTy, getThrowInfoType()->getPointerTo()}; + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false); + auto *Fn = cast( + CGM.CreateRuntimeFunction(FTy, "_CxxThrowException")); + // _CxxThrowException is stdcall on 32-bit x86 platforms. + if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) + Fn->setCallingConv(llvm::CallingConv::X86_StdCall); + return Fn; + } + + llvm::Constant *getCatchableType(QualType T, + uint32_t NVOffset = 0, + int32_t VBPtrOffset = -1, + uint32_t VBIndex = 0); + + llvm::GlobalVariable *getCatchableTypeArray(QualType T); + + llvm::GlobalVariable *getThrowInfo(QualType T); + private: typedef std::pair VFTableIdTy; typedef llvm::DenseMap VTablesMapTy; @@ -596,6 +674,12 @@ llvm::StructType *BaseClassDescriptorType; llvm::StructType *ClassHierarchyDescriptorType; llvm::StructType *CompleteObjectLocatorType; + + llvm::DenseMap CatchableTypeArrays; + + llvm::StructType *CatchableTypeType; + llvm::DenseMap CatchableTypeArrayTypeMap; + llvm::StructType *ThrowInfoType; }; } @@ -676,24 +760,11 @@ CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType); } -static llvm::Function *getRethrowFn(CodeGenModule &CGM) { - // _CxxThrowException takes two pointer width arguments: a value and a context - // object which points to a TypeInfo object. - llvm::Type *ArgTypes[] = {CGM.Int8PtrTy, CGM.Int8PtrTy}; - llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false); - auto *Fn = cast( - CGM.CreateRuntimeFunction(FTy, "_CxxThrowException")); - // _CxxThrowException is stdcall on 32-bit x86 platforms. - if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) - Fn->setCallingConv(llvm::CallingConv::X86_StdCall); - return Fn; -} - void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) { - llvm::Value *Args[] = {llvm::ConstantPointerNull::get(CGM.Int8PtrTy), - llvm::ConstantPointerNull::get(CGM.Int8PtrTy)}; - auto *Fn = getRethrowFn(CGM); + llvm::Value *Args[] = { + llvm::ConstantPointerNull::get(CGM.Int8PtrTy), + llvm::ConstantPointerNull::get(getThrowInfoType()->getPointerTo())}; + auto *Fn = getThrowFn(); if (isNoReturn) CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, Args); else @@ -2913,7 +2984,7 @@ auto Type = ABI.getClassHierarchyDescriptorType(); auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, /*Initializer=*/nullptr, - MangledName.c_str()); + StringRef(MangledName)); if (CHD->isWeakForLinker()) CHD->setComdat(CGM.getModule().getOrInsertComdat(CHD->getName())); @@ -2946,9 +3017,10 @@ llvm::Type *PtrType = ABI.getImageRelativeType( ABI.getBaseClassDescriptorType()->getPointerTo()); auto *ArrType = llvm::ArrayType::get(PtrType, Classes.size() + 1); - auto *BCA = new llvm::GlobalVariable( - Module, ArrType, - /*Constant=*/true, Linkage, /*Initializer=*/nullptr, MangledName.c_str()); + auto *BCA = + new llvm::GlobalVariable(Module, ArrType, + /*Constant=*/true, Linkage, + /*Initializer=*/nullptr, StringRef(MangledName)); if (BCA->isWeakForLinker()) BCA->setComdat(CGM.getModule().getOrInsertComdat(BCA->getName())); @@ -2988,9 +3060,9 @@ // Forward-declare the base class descriptor. auto Type = ABI.getBaseClassDescriptorType(); - auto BCD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, - /*Initializer=*/nullptr, - MangledName.c_str()); + auto BCD = + new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, + /*Initializer=*/nullptr, StringRef(MangledName)); if (BCD->isWeakForLinker()) BCD->setComdat(CGM.getModule().getOrInsertComdat(BCD->getName())); @@ -3036,7 +3108,7 @@ // Forward-declare the complete object locator. llvm::StructType *Type = ABI.getCompleteObjectLocatorType(); auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, - /*Initializer=*/nullptr, MangledName.c_str()); + /*Initializer=*/nullptr, StringRef(MangledName)); // Initialize the CompleteObjectLocator. llvm::Constant *Fields[] = { @@ -3089,7 +3161,7 @@ CGM.getModule(), TypeDescriptorType, /*Constant=*/false, getLinkageForRTTI(Type), llvm::ConstantStruct::get(TypeDescriptorType, Fields), - MangledName.c_str()); + StringRef(MangledName)); if (Var->isWeakForLinker()) Var->setComdat(CGM.getModule().getOrInsertComdat(Var->getName())); return llvm::ConstantExpr::getBitCast(Var, CGM.Int8PtrTy); @@ -3146,3 +3218,272 @@ } emitCXXDestructor(CGM, cast(MD), Type); } + +llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T, + uint32_t NVOffset, + int32_t VBPtrOffset, + uint32_t VBIndex) { + assert(!T->isReferenceType()); + + uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity(); + SmallString<256> MangledName; + { + llvm::raw_svector_ostream Out(MangledName); + getMangleContext().mangleCXXCatchableType(T, Size, Out); + } + if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName)) + return getImageRelativeConstant(GV); + + // The TypeDescriptor is used by the runtime to determine of a catch handler + // is appropriate for the exception object. + llvm::Constant *TD = getImageRelativeConstant(getAddrOfRTTIDescriptor(T)); + + // The runtime is responsible for calling the copy constructor if the + // exception is caught by value. + llvm::Constant *CopyCtor = + getImageRelativeConstant(llvm::Constant::getNullValue(CGM.Int8PtrTy)); + + bool IsScalar = true; + bool HasVirtualBases = false; + bool IsStdBadAlloc = false; // std::bad_alloc is special for some reason. + if (T->getAsCXXRecordDecl()) { + IsScalar = false; + // TODO: Fill in the CopyCtor here! This is not trivial due to + // copy-constructors possessing things like default arguments. + } + QualType PointeeType = T; + if (T->isPointerType()) + PointeeType = T->getPointeeType(); + if (const CXXRecordDecl *RD = PointeeType->getAsCXXRecordDecl()) { + HasVirtualBases = RD->getNumVBases() > 0; + if (IdentifierInfo *II = RD->getIdentifier()) + IsStdBadAlloc = II->isStr("bad_alloc") && RD->isInStdNamespace(); + } + + // Encode the relevant CatchableType properties into the Flags bitfield. + // FIXME: Figure out how bits 2 or 8 can get set. + uint32_t Flags = 0; + if (IsScalar) + Flags |= 1; + if (HasVirtualBases) + Flags |= 4; + if (IsStdBadAlloc) + Flags |= 16; + + llvm::Constant *Fields[] = { + llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags + TD, // TypeDescriptor + llvm::ConstantInt::get(CGM.IntTy, NVOffset), // NonVirtualAdjustment + llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset), // OffsetToVBPtr + llvm::ConstantInt::get(CGM.IntTy, VBIndex), // VBTableIndex + llvm::ConstantInt::get(CGM.IntTy, Size), // Size + CopyCtor // CopyCtor + }; + llvm::StructType *CTType = getCatchableTypeType(); + auto *GV = new llvm::GlobalVariable( + CGM.getModule(), CTType, /*Constant=*/true, getLinkageForRTTI(T), + llvm::ConstantStruct::get(CTType, Fields), StringRef(MangledName)); + if (GV->isWeakForLinker()) + GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName())); + GV->setUnnamedAddr(true); + return getImageRelativeConstant(GV); +} + +llvm::GlobalVariable *MicrosoftCXXABI::getCatchableTypeArray(QualType T) { + assert(!T->isReferenceType()); + + // See if we've already generated a CatchableTypeArray for this type before. + llvm::GlobalVariable *&CTA = CatchableTypeArrays[T]; + if (CTA) + return CTA; + + // Ensure that we don't have duplicate entries in our CatchableTypeArray by + // using a SmallSetVector. Duplicates may arise due to virtual bases + // occurring more than once in the hierarchy. + llvm::SmallSetVector CatchableTypes; + + // C++14 [except.handle]p3: + // A handler is a match for an exception object of type E if [...] + // - the handler is of type cv T or cv T& and T is an unambiguous public + // base class of E, or + // - the handler is of type cv T or const T& where T is a pointer type and + // E is a pointer type that can be converted to T by [...] + // - a standard pointer conversion (4.10) not involving conversions to + // pointers to private or protected or ambiguous classes + const CXXRecordDecl *MostDerivedClass = nullptr; + bool IsPointer = T->isPointerType(); + if (IsPointer) + MostDerivedClass = T->getPointeeType()->getAsCXXRecordDecl(); + else + MostDerivedClass = T->getAsCXXRecordDecl(); + + // Collect all the unambiguous public bases of the MostDerivedClass. + if (MostDerivedClass) { + const ASTContext &Context = CGM.getContext(); + const ASTRecordLayout &MostDerivedLayout = + Context.getASTRecordLayout(MostDerivedClass); + MicrosoftVTableContext &VTableContext = CGM.getMicrosoftVTableContext(); + SmallVector Classes; + serializeClassHierarchy(Classes, MostDerivedClass); + Classes.front().initialize(/*Parent=*/nullptr, /*Specifier=*/nullptr); + detectAmbiguousBases(Classes); + for (const MSRTTIClass &Class : Classes) { + // Skip any ambiguous or private bases. + if (Class.Flags & + (MSRTTIClass::IsPrivateOnPath | MSRTTIClass::IsAmbiguous)) + continue; + // Write down how to convert from a derived pointer to a base pointer. + uint32_t OffsetInVBTable = 0; + int32_t VBPtrOffset = -1; + if (Class.VirtualRoot) { + OffsetInVBTable = + VTableContext.getVBTableIndex(MostDerivedClass, Class.VirtualRoot)*4; + VBPtrOffset = MostDerivedLayout.getVBPtrOffset().getQuantity(); + } + + // Turn our record back into a pointer if the exception object is a + // pointer. + QualType RTTITy = QualType(Class.RD->getTypeForDecl(), 0); + if (IsPointer) + RTTITy = Context.getPointerType(RTTITy); + CatchableTypes.insert(getCatchableType(RTTITy, Class.OffsetInVBase, + VBPtrOffset, OffsetInVBTable)); + } + } + + // C++14 [except.handle]p3: + // A handler is a match for an exception object of type E if + // - The handler is of type cv T or cv T& and E and T are the same type + // (ignoring the top-level cv-qualifiers) + CatchableTypes.insert(getCatchableType(T)); + + // C++14 [except.handle]p3: + // A handler is a match for an exception object of type E if + // - the handler is of type cv T or const T& where T is a pointer type and + // E is a pointer type that can be converted to T by [...] + // - a standard pointer conversion (4.10) not involving conversions to + // pointers to private or protected or ambiguous classes + // + // All pointers are convertible to void so ensure that it is in the + // CatchableTypeArray. + if (IsPointer) + CatchableTypes.insert(getCatchableType(getContext().VoidPtrTy)); + + uint32_t NumEntries = CatchableTypes.size(); + llvm::Type *CTType = + getImageRelativeType(getCatchableTypeType()->getPointerTo()); + llvm::ArrayType *AT = llvm::ArrayType::get(CTType, NumEntries); + llvm::StructType *CTAType = getCatchableTypeArrayType(NumEntries); + llvm::Constant *Fields[] = { + llvm::ConstantInt::get(CGM.IntTy, NumEntries), // NumEntries + llvm::ConstantArray::get( + AT, llvm::makeArrayRef(CatchableTypes.begin(), + CatchableTypes.end())) // CatchableTypes + }; + SmallString<256> MangledName; + { + llvm::raw_svector_ostream Out(MangledName); + getMangleContext().mangleCXXCatchableTypeArray(T, NumEntries, Out); + } + CTA = new llvm::GlobalVariable( + CGM.getModule(), CTAType, /*Constant=*/true, getLinkageForRTTI(T), + llvm::ConstantStruct::get(CTAType, Fields), StringRef(MangledName)); + if (CTA->isWeakForLinker()) + CTA->setComdat(CGM.getModule().getOrInsertComdat(CTA->getName())); + CTA->setUnnamedAddr(true); + return CTA; +} + +llvm::GlobalVariable *MicrosoftCXXABI::getThrowInfo(QualType T) { + // C++14 [except.handle]p3: + // A handler is a match for an exception object of type E if [...] + // - the handler is of type cv T or const T& where T is a pointer type and + // E is a pointer type that can be converted to T by [...] + // - a qualification conversion + bool IsConst = false, IsVolatile = false; + QualType PointeeType = T->getPointeeType(); + if (!PointeeType.isNull()) { + IsConst = PointeeType.isConstQualified(); + IsVolatile = PointeeType.isVolatileQualified(); + } + T = getContext().getExceptionObjectType(T); + + // The CatchableTypeArray enumerates the various (CV-unqualified) types that + // the exception object may be caught as. + llvm::GlobalVariable *CTA = getCatchableTypeArray(T); + // The first field in a CatchableTypeArray is the number of CatchableTypes. + // This is used as a component of the mangled name which means that we need to + // know what it is in order to see if we have previously generated the + // ThrowInfo. + uint32_t NumEntries = + cast(CTA->getInitializer()->getAggregateElement(0U)) + ->getLimitedValue(); + + SmallString<256> MangledName; + { + llvm::raw_svector_ostream Out(MangledName); + getMangleContext().mangleCXXThrowInfo(T, IsConst, IsVolatile, NumEntries, + Out); + } + + // Reuse a previously generated ThrowInfo if we have generated an appropriate + // one before. + if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName)) + return GV; + + // The RTTI TypeDescriptor uses an unqualified type but catch clauses must + // be at least as CV qualified. Encode this requirement into the Flags + // bitfield. + uint32_t Flags = 0; + if (IsConst) + Flags |= 1; + if (IsVolatile) + Flags |= 2; + + // The cleanup-function (a destructor) must be called when the exception + // object's lifetime ends. + llvm::Constant *CleanupFn = llvm::Constant::getNullValue(CGM.Int8PtrTy); + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + if (CXXDestructorDecl *DtorD = RD->getDestructor()) + if (!DtorD->isTrivial()) + CleanupFn = llvm::ConstantExpr::getBitCast( + CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete), + CGM.Int8PtrTy); + // This is unused as far as we can tell, initialize it to null. + llvm::Constant *ForwardCompat = + getImageRelativeConstant(llvm::Constant::getNullValue(CGM.Int8PtrTy)); + llvm::Constant *PointerToCatchableTypes = getImageRelativeConstant( + llvm::ConstantExpr::getBitCast(CTA, CGM.Int8PtrTy)); + llvm::StructType *TIType = getThrowInfoType(); + llvm::Constant *Fields[] = { + llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags + getImageRelativeConstant(CleanupFn), // CleanupFn + ForwardCompat, // ForwardCompat + PointerToCatchableTypes // CatchableTypeArray + }; + auto *GV = new llvm::GlobalVariable( + CGM.getModule(), TIType, /*Constant=*/true, getLinkageForRTTI(T), + llvm::ConstantStruct::get(TIType, Fields), StringRef(MangledName)); + if (GV->isWeakForLinker()) + GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName())); + GV->setUnnamedAddr(true); + return GV; +} + +void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { + const Expr *SubExpr = E->getSubExpr(); + QualType ThrowType = SubExpr->getType(); + // The exception object lives on the stack and it's address is passed to the + // runtime function. + llvm::AllocaInst *AI = CGF.CreateMemTemp(ThrowType); + CGF.EmitAnyExprToMem(SubExpr, AI, ThrowType.getQualifiers(), + /*IsInit=*/true); + + // The so-called ThrowInfo is used to describe how the exception object may be + // caught. + llvm::GlobalVariable *TI = getThrowInfo(ThrowType); + + // Call into the runtime to throw the exception. + llvm::Value *Args[] = {CGF.Builder.CreateBitCast(AI, CGM.Int8PtrTy), TI}; + CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args); +} Index: cfe/trunk/test/CodeGenCXX/microsoft-abi-throw.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-throw.cpp +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-throw.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 %s -fcxx-exceptions | FileCheck %s + +// CHECK-DAG: @"\01??_R0?AUY@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUY@@\00" }, comdat +// CHECK-DAG: @"_CT??_R0?AUY@@@88" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUY@@@8" to i8*), i32 0, i32 -1, i32 0, i32 8, i8* null }, comdat +// CHECK-DAG: @"\01??_R0?AUZ@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUZ@@\00" }, comdat +// CHECK-DAG: @"_CT??_R0?AUZ@@@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUZ@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* null }, comdat +// CHECK-DAG: @"\01??_R0?AUW@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUW@@\00" }, comdat +// CHECK-DAG: @"_CT??_R0?AUW@@@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUW@@@8" to i8*), i32 4, i32 -1, i32 0, i32 4, i8* null }, comdat +// CHECK-DAG: @"\01??_R0?AUM@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUM@@\00" }, comdat +// CHECK-DAG: @"_CT??_R0?AUM@@@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUM@@@8" to i8*), i32 8, i32 -1, i32 0, i32 1, i8* null }, comdat +// CHECK-DAG: @"\01??_R0?AUV@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUV@@\00" }, comdat +// CHECK-DAG: @"_CT??_R0?AUV@@@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUV@@@8" to i8*), i32 0, i32 4, i32 4, i32 1, i8* null }, comdat +// CHECK-DAG: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@88", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@84", %eh.CatchableType* @"_CT??_R0?AUM@@@81", %eh.CatchableType* @"_CT??_R0?AUV@@@81"] }, comdat +// CHECK-DAG: @"_TI5?AUY@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* bitcast (void (%struct.Y*)* @"\01??_DY@@QAE@XZ" to i8*), i8* null, i8* bitcast (%eh.CatchableTypeArray.5* @"_CTA5?AUY@@" to i8*) }, comdat + + +struct N { ~N(); }; +struct M : private N {}; +struct X {}; +struct Z {}; +struct V : private X {}; +struct W : M, virtual V {}; +struct Y : Z, W, virtual V {}; + +void f(const Y &y) { + // CHECK-LABEL: @"\01?f@@YAXABUY@@@Z" + // CHECK: call x86_thiscallcc %struct.Y* @"\01??0Y@@QAE@ABU0@@Z"(%struct.Y* %[[mem:.*]], %struct.Y* + // CHECK: %[[cast:.*]] = bitcast %struct.Y* %[[mem]] to i8* + // CHECK: call void @_CxxThrowException(i8* %[[cast]], %eh.ThrowInfo* @"_TI5?AUY@@") #4 + throw y; +} Index: cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp @@ -1,6 +1,11 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTRY | FileCheck %s -check-prefix=TRY // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTHROW | FileCheck %s -check-prefix=THROW +// THROW-DAG: @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +// THROW-DAG: @"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i32 -1, i32 0, i32 4, i8* null }, comdat +// THROW-DAG: @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, comdat +// THROW-DAG: @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, comdat + void external(); inline void not_emitted() { @@ -19,7 +24,9 @@ } #endif #ifdef THROW - // THROW: call void @"\01?terminate@@YAXXZ" + // THROW: store i32 42, i32* %[[mem_for_throw:.*]] + // THROW: %[[cast:.*]] = bitcast i32* %[[mem_for_throw]] to i8* + // THROW: call void @_CxxThrowException(i8* %[[cast]], %eh.ThrowInfo* @_TI1H) throw int(42); #endif return rv;