Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -2193,6 +2193,12 @@ /// it is not used. bool DeclMustBeEmitted(const Decl *D); + const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *RD); + + void addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD); + void setManglingNumber(const NamedDecl *ND, unsigned Number); unsigned getManglingNumber(const NamedDecl *ND) const; Index: include/clang/AST/Mangle.h =================================================================== --- include/clang/AST/Mangle.h +++ include/clang/AST/Mangle.h @@ -203,8 +203,8 @@ 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 mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, + uint32_t Size, raw_ostream &Out) = 0; virtual void mangleCXXRTTIBaseClassDescriptor( const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8189,6 +8189,19 @@ return ABI->createMangleNumberingContext(); } +const CXXConstructorDecl * +ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) { + return ABI->getCopyConstructorForExceptionObject( + cast(RD->getFirstDecl())); +} + +void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD) { + return ABI->addCopyConstructorForExceptionObject( + cast(RD->getFirstDecl()), + cast(CD->getFirstDecl())); +} + void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; } Index: lib/AST/CXXABI.h =================================================================== --- lib/AST/CXXABI.h +++ lib/AST/CXXABI.h @@ -20,6 +20,7 @@ namespace clang { class ASTContext; +class CXXConstructorDecl; class MemberPointerType; class MangleNumberingContext; @@ -41,6 +42,14 @@ /// Returns a new mangling number context for this C++ ABI. virtual MangleNumberingContext *createMangleNumberingContext() const = 0; + + /// Adds a mapping from class to copy constructor for this C++ ABI. + virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *, + CXXConstructorDecl *) = 0; + + /// Retrieves the mapping from class to copy constructor for this C++ ABI. + virtual const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0; }; /// Creates an instance of a C++ ABI class. Index: lib/AST/ItaniumCXXABI.cpp =================================================================== --- lib/AST/ItaniumCXXABI.cpp +++ lib/AST/ItaniumCXXABI.cpp @@ -133,6 +133,14 @@ return Layout.getNonVirtualSize() == PointerSize; } + const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { + return nullptr; + } + + void addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD) override {} + MangleNumberingContext *createMangleNumberingContext() const override { return new ItaniumNumberingContext(); } Index: lib/AST/MicrosoftCXXABI.cpp =================================================================== --- lib/AST/MicrosoftCXXABI.cpp +++ lib/AST/MicrosoftCXXABI.cpp @@ -63,6 +63,8 @@ class MicrosoftCXXABI : public CXXABI { ASTContext &Context; + llvm::SmallDenseMap RecordToCopyCtor; + public: MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } @@ -82,13 +84,26 @@ return false; const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - + // In the Microsoft ABI, classes can have one or two vtable pointers. - CharUnits PointerSize = - Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + CharUnits PointerSize = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; - } + } + + const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { + return RecordToCopyCtor[RD]; + } + + void + addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD) override { + assert(CD != nullptr); + assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD); + RecordToCopyCtor[RD] = CD; + } MangleNumberingContext *createMangleNumberingContext() const override { return new MicrosoftNumberingContext(); Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -114,8 +114,8 @@ 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 mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, + 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, @@ -2307,13 +2307,25 @@ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); } -void MicrosoftMangleContextImpl::mangleCXXCatchableType(QualType T, - uint32_t Size, - raw_ostream &Out) { +void MicrosoftMangleContextImpl::mangleCXXCatchableType( + QualType T, const CXXConstructorDecl *CD, 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() << "_CT"; + + llvm::SmallString<64> RTTIMangling; + { + llvm::raw_svector_ostream Stream(RTTIMangling); + mangleCXXRTTI(T, Stream); + } + Mangler.getStream() << RTTIMangling.substr(1); + + llvm::SmallString<64> CopyCtorMangling; + if (CD) { + llvm::raw_svector_ostream Stream(CopyCtorMangling); + mangleCXXCtor(CD, Ctor_Complete, Stream); + } + Mangler.getStream() << CopyCtorMangling.substr(1); + Mangler.getStream() << Size; } Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -17,6 +17,7 @@ #include "CGCXXABI.h" #include "CGVTables.h" #include "CodeGenModule.h" +#include "CodeGenTypes.h" #include "TargetInfo.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -3225,11 +3226,14 @@ uint32_t VBIndex) { assert(!T->isReferenceType()); + CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + const CXXConstructorDecl *CD = + RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr; uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity(); SmallString<256> MangledName; { llvm::raw_svector_ostream Out(MangledName); - getMangleContext().mangleCXXCatchableType(T, Size, Out); + getMangleContext().mangleCXXCatchableType(T, CD, Size, Out); } if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName)) return getImageRelativeConstant(GV); @@ -3241,16 +3245,15 @@ // 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)); + CD ? llvm::ConstantExpr::getBitCast( + CGM.getAddrOfCXXStructor(CD, StructorType::Complete), + CGM.Int8PtrTy) + : llvm::Constant::getNullValue(CGM.Int8PtrTy); + CopyCtor = getImageRelativeConstant(CopyCtor); - bool IsScalar = true; + bool IsScalar = !RD; 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(); Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -657,6 +657,55 @@ CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); } +static void +collectPublicBases(CXXRecordDecl *RD, + llvm::DenseMap &SubobjectsSeen, + llvm::SmallPtrSetImpl &VBases, + llvm::SetVector &PublicSubobjectsSeen, + bool ParentIsPublic) { + for (const CXXBaseSpecifier &BS : RD->bases()) { + CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); + bool NewSubobject; + // Virtual bases constitute the same subobject. Non-virtual bases are + // always distinct subobjects. + if (BS.isVirtual()) + NewSubobject = VBases.insert(BaseDecl).second; + else + NewSubobject = true; + + if (NewSubobject) + ++SubobjectsSeen[BaseDecl]; + + // Only add subobjects which have public access throughout the entire chain. + bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; + if (PublicPath) + PublicSubobjectsSeen.insert(BaseDecl); + + // Recurse on to each base subobject. + collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, + PublicPath); + } +} + +static void getUnambiguousPublicSubobjects( + CXXRecordDecl *RD, llvm::SmallVectorImpl &Objects) { + llvm::DenseMap SubobjectsSeen; + llvm::SmallSet VBases; + llvm::SetVector PublicSubobjectsSeen; + SubobjectsSeen[RD] = 1; + PublicSubobjectsSeen.insert(RD); + collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, + /*ParentIsPublic=*/true); + + for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { + // Skip ambiguous objects. + if (SubobjectsSeen[PublicSubobject] > 1) + continue; + + Objects.push_back(PublicSubobject); + } +} + /// CheckCXXThrowOperand - Validate the operand of a throw. ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, bool IsThrownVarInScope) { @@ -723,18 +772,29 @@ return E; // If the class has a destructor, we must be able to call it. - if (RD->hasIrrelevantDestructor()) - return E; + if (!RD->hasIrrelevantDestructor()) { + if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { + MarkFunctionReferenced(E->getExprLoc(), Destructor); + CheckDestructorAccess(E->getExprLoc(), Destructor, + PDiag(diag::err_access_dtor_exception) << Ty); + if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) + return ExprError(); + } + } - CXXDestructorDecl *Destructor = LookupDestructor(RD); - if (!Destructor) - return E; + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + llvm::SmallVector UnambiguousPublicSubobjects; + getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); + for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { + if (CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0)) { + if (CD->isTrivial()) + continue; + MarkFunctionReferenced(E->getExprLoc(), CD); + Context.addCopyConstructorForExceptionObject(Subobject, CD); + } + } + } - MarkFunctionReferenced(E->getExprLoc(), Destructor); - CheckDestructorAccess(E->getExprLoc(), Destructor, - PDiag(diag::err_access_dtor_exception) << Ty); - if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) - return ExprError(); return E; } Index: test/CodeGenCXX/microsoft-abi-throw.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-throw.cpp +++ test/CodeGenCXX/microsoft-abi-throw.cpp @@ -1,16 +1,16 @@ // 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: @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8" = 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* bitcast (%struct.Y* (%struct.Y*, %struct.Y*, i32)* @"\01??0Y@@QAE@ABU0@@Z" to i8*) }, 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: @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z4" = 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* bitcast (%struct.W* (%struct.W*, %struct.W*, i32)* @"\01??0W@@QAE@ABU0@@Z" to i8*) }, 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: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z4", %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