- Add a test to exercise throw
http://reviews.llvm.org/D8066
Files:
include/clang/AST/Mangle.h
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/CGCXXABI.h
lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/ItaniumCXXABI.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/microsoft-abi-throw.cpp
test/CodeGenCXX/microsoft-abi-try-throw.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/AST/Mangle.h
===================================================================
--- include/clang/AST/Mangle.h
+++ 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: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -110,6 +110,12 @@
void mangleCXXVBTable(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> 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: lib/CodeGen/CGCXXABI.h
===================================================================
--- lib/CodeGen/CGCXXABI.h
+++ 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: lib/CodeGen/CGException.cpp
===================================================================
--- lib/CodeGen/CGException.cpp
+++ 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,30 +361,29 @@
// 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<FreeException>(EHCleanup, addr);
- EHScopeStack::stable_iterator cleanup = CGF.EHStack.stable_begin();
+ pushFullExprCleanup<FreeException>(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
// must call std::terminate() if that constructor throws, because
// technically that copy occurs after the exception expression is
// 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<llvm::Instruction>(typedAddr));
+ DeactivateCleanupBlock(cleanup, cast<llvm::Instruction>(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<Stmt *>(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<RecordType>()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(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<Stmt *>(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: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ 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: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ 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<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(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: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ 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,72 @@
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::SmallString<23> CTATypeName("eh.CatchableTypeArray.");
+ CTATypeName += llvm::utostr(NumEntries);
+ llvm::StructType *&CatchableTypeArrayType =
+ CatchableTypeArrayTypeMap[NumEntries];
+ if (CatchableTypeArrayType)
+ return CatchableTypeArrayType;
+ 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() {
+ llvm::Type *Args[] = {CGM.Int8PtrTy, getThrowInfoType()->getPointerTo()};
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
+
+ return CGM.CreateRuntimeFunction(FTy, "_CxxThrowException");
+ }
+
+ 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<const CXXRecordDecl *, CharUnits> VFTableIdTy;
typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy;
@@ -596,6 +667,12 @@
llvm::StructType *BaseClassDescriptorType;
llvm::StructType *ClassHierarchyDescriptorType;
llvm::StructType *CompleteObjectLocatorType;
+
+ llvm::DenseMap<QualType, llvm::GlobalVariable *> CatchableTypeArrays;
+
+ llvm::StructType *CatchableTypeType;
+ llvm::DenseMap<uint32_t, llvm::StructType *> CatchableTypeArrayTypeMap;
+ llvm::StructType *ThrowInfoType;
};
}
@@ -3146,3 +3223,265 @@
}
emitCXXDestructor(CGM, cast<CXXDestructorDecl>(MD), Type);
}
+
+llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
+ uint32_t NVOffset,
+ int32_t VBPtrOffset,
+ uint32_t VBIndex) {
+ const 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), MangledName.c_str());
+ if (GV->isWeakForLinker())
+ GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName()));
+ return getImageRelativeConstant(GV);
+}
+
+llvm::GlobalVariable *MicrosoftCXXABI::getCatchableTypeArray(QualType T) {
+ // 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<llvm::Constant *, 2> 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;
+ const 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<MSRTTIClass, 8> 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));
+
+ const 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), MangledName.c_str());
+ if (CTA->isWeakForLinker())
+ CTA->setComdat(CGM.getModule().getOrInsertComdat(CTA->getName()));
+ 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<llvm::ConstantInt>(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), MangledName.c_str());
+ if (GV->isWeakForLinker())
+ GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName()));
+ 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: test/CodeGenCXX/microsoft-abi-throw.cpp
===================================================================
--- /dev/null
+++ 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 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 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 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 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 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 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 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: test/CodeGenCXX/microsoft-abi-try-throw.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-try-throw.cpp
+++ 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 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 constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, comdat
+// THROW-DAG: @_TI1H = linkonce_odr 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;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits