From dfa6d2067c8c782c83be69a61fe59a0240535df6 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Wed, 11 Mar 2015 18:36:39 +0000 Subject: [PATCH] MS ABI: Implement copy-ctor closures, finish implementing throw This adds support for copy-constructor closures. These are generated when the C++ runtime has to call a copy-constructor with a particular calling convention or with default arguments substituted in to the call. Because the runtime has no mechanism to call the function with a different calling convention or know-how to evaluate the default arguments at run-time, we create a thunk which will do all the appropriate work and package it in a way the runtime can use. Differential Revision: http://reviews.llvm.org/D8225 llvm-svn: 231952 --- clang/include/clang/AST/ASTContext.h | 6 ++ clang/include/clang/AST/Mangle.h | 6 +- clang/include/clang/Basic/ABI.h | 8 +- clang/lib/AST/ASTContext.cpp | 12 +++ clang/lib/AST/CXXABI.h | 7 ++ clang/lib/AST/ItaniumCXXABI.cpp | 8 ++ clang/lib/AST/ItaniumMangle.cpp | 3 + clang/lib/AST/MicrosoftCXXABI.cpp | 12 +++ clang/lib/AST/MicrosoftMangle.cpp | 89 ++++++++++++++---- clang/lib/CodeGen/CGCall.cpp | 16 ++++ clang/lib/CodeGen/CodeGenTypes.h | 4 + clang/lib/CodeGen/MicrosoftCXXABI.cpp | 129 ++++++++++++++++++++++++-- clang/lib/Sema/SemaExprCXX.cpp | 45 ++++++++- clang/test/CodeGenCXX/microsoft-abi-throw.cpp | 54 ++++++++++- 14 files changed, 363 insertions(+), 36 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b62760f..48e3451 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2201,6 +2201,12 @@ public: void addCopyConstructorForExceptionObject(CXXRecordDecl *RD, CXXConstructorDecl *CD); + void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE); + + Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx); + void setManglingNumber(const NamedDecl *ND, unsigned Number); unsigned getManglingNumber(const NamedDecl *ND) const; diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index 912c56a..aa644b2 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -204,9 +204,9 @@ public: raw_ostream &Out) = 0; virtual void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, - uint32_t Size, uint32_t NVOffset, - int32_t VBPtrOffset, uint32_t VBIndex, - raw_ostream &Out) = 0; + CXXCtorType CT, uint32_t Size, + uint32_t NVOffset, int32_t VBPtrOffset, + uint32_t VBIndex, raw_ostream &Out) = 0; virtual void mangleCXXRTTIBaseClassDescriptor( const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, diff --git a/clang/include/clang/Basic/ABI.h b/clang/include/clang/Basic/ABI.h index bd24679..5943b3f 100644 --- a/clang/include/clang/Basic/ABI.h +++ b/clang/include/clang/Basic/ABI.h @@ -22,9 +22,11 @@ namespace clang { /// \brief C++ constructor types. enum CXXCtorType { - Ctor_Complete, ///< Complete object ctor - Ctor_Base, ///< Base object ctor - Ctor_Comdat ///< The COMDAT used for ctors + Ctor_Complete, ///< Complete object ctor + Ctor_Base, ///< Base object ctor + Ctor_Comdat, ///< The COMDAT used for ctors + Ctor_CopyingClosure, ///< Copying closure variant of a ctor + Ctor_DefaultClosure, ///< Default closure variant of a ctor }; /// \brief C++ destructor types. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 20d2aa6..e92b335 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8210,6 +8210,18 @@ void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD, cast(CD->getFirstDecl())); } +void ASTContext::addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) { + ABI->addDefaultArgExprForConstructor( + cast(CD->getFirstDecl()), ParmIdx, DAE); +} + +Expr *ASTContext::getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) { + return ABI->getDefaultArgExprForConstructor( + cast(CD->getFirstDecl()), ParmIdx); +} + void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; } diff --git a/clang/lib/AST/CXXABI.h b/clang/lib/AST/CXXABI.h index 62c96f9..dad2264 100644 --- a/clang/lib/AST/CXXABI.h +++ b/clang/lib/AST/CXXABI.h @@ -21,6 +21,7 @@ namespace clang { class ASTContext; class CXXConstructorDecl; +class Expr; class MemberPointerType; class MangleNumberingContext; @@ -50,6 +51,12 @@ public: /// Retrieves the mapping from class to copy constructor for this C++ ABI. virtual const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0; + + virtual void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) = 0; + + virtual Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 13d4dbf1..7420782 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -141,6 +141,14 @@ public: void addCopyConstructorForExceptionObject(CXXRecordDecl *RD, CXXConstructorDecl *CD) override {} + void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) override {} + + Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) override { + return nullptr; + } + MangleNumberingContext *createMangleNumberingContext() const override { return new ItaniumNumberingContext(); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 13136b3..f890719 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3442,6 +3442,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { case Ctor_Comdat: Out << "C5"; break; + case Ctor_DefaultClosure: + case Ctor_CopyingClosure: + llvm_unreachable("closure constructors don't exist for the Itanium ABI!"); } } diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 71b21bf..fb3beff 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -64,6 +64,8 @@ public: class MicrosoftCXXABI : public CXXABI { ASTContext &Context; llvm::SmallDenseMap RecordToCopyCtor; + llvm::SmallDenseMap, Expr *> + CtorToDefaultArgExpr; public: MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } @@ -92,6 +94,16 @@ public: Layout.getNonVirtualSize() == PointerSize * 2; } + void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) override { + CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)] = DAE; + } + + Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) override { + return CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)]; + } + const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { return RecordToCopyCtor[RD]; diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 073e798..f56da26 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -67,11 +67,15 @@ static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { return getEffectiveDeclContext(cast(DC)); } -static const FunctionDecl *getStructor(const FunctionDecl *fn) { - if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) - return ftd->getTemplatedDecl(); +static const FunctionDecl *getStructor(const NamedDecl *ND) { + if (const auto *FTD = dyn_cast(ND)) + return FTD->getTemplatedDecl(); - return fn; + const auto *FD = cast(ND); + if (const auto *FTD = FD->getPrimaryTemplate()) + return FTD->getTemplatedDecl(); + + return FD; } static bool isLambda(const NamedDecl *ND) { @@ -115,7 +119,7 @@ public: void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries, raw_ostream &Out) override; void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, - uint32_t Size, uint32_t NVOffset, + CXXCtorType CT, uint32_t Size, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex, raw_ostream &Out) override; void mangleCXXRTTI(QualType T, raw_ostream &Out) override; @@ -224,6 +228,12 @@ public: 64) {} MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, + const CXXConstructorDecl *D, CXXCtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) {} + + MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == @@ -284,6 +294,7 @@ private: void mangleDecayedArrayType(const ArrayType *T); void mangleArrayType(const ArrayType *T); void mangleFunctionClass(const FunctionDecl *FD); + void mangleCallingConvention(CallingConv CC); void mangleCallingConvention(const FunctionType *T); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); void mangleExpression(const Expr *E); @@ -770,12 +781,18 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, llvm_unreachable("Can't mangle Objective-C selector names here!"); case DeclarationName::CXXConstructorName: - if (ND == Structor) { - assert(StructorType == Ctor_Complete && - "Should never be asked to mangle a ctor other than complete"); + if (Structor == getStructor(ND)) { + if (StructorType == Ctor_CopyingClosure) { + Out << "?_O"; + return; + } + if (StructorType == Ctor_DefaultClosure) { + Out << "?_F"; + return; + } } Out << "?0"; - break; + return; case DeclarationName::CXXDestructorName: if (ND == Structor) @@ -1566,12 +1583,22 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, SourceRange Range; if (D) Range = D->getSourceRange(); - bool IsStructor = false, HasThisQuals = ForceThisQuals; + bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false; + CallingConv CC = T->getCallConv(); if (const CXXMethodDecl *MD = dyn_cast_or_null(D)) { if (MD->isInstance()) HasThisQuals = true; - if (isa(MD) || isa(MD)) + if (isa(MD)) { + IsStructor = true; + } else if (isa(MD)) { IsStructor = true; + IsCtorClosure = (StructorType == Ctor_CopyingClosure || + StructorType == Ctor_DefaultClosure) && + getStructor(MD) == Structor; + if (IsCtorClosure) + CC = getASTContext().getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true); + } } // If this is a C++ instance method, mangle the CVR qualifiers for the @@ -1583,7 +1610,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, mangleQualifiers(Quals, /*IsMember=*/false); } - mangleCallingConvention(T); + mangleCallingConvention(CC); // ::= // ::= @ # structors (they have no declared return type) @@ -1597,6 +1624,28 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); return; } + if (IsCtorClosure) { + // Default constructor closure and copy constructor closure both return + // void. + Out << 'X'; + + if (StructorType == Ctor_DefaultClosure) { + // Default constructor closure always has no arguments. + Out << 'X'; + } else if (StructorType == Ctor_CopyingClosure) { + // Copy constructor closure always takes an unqualified reference. + mangleArgumentType(getASTContext().getLValueReferenceType( + Proto->getParamType(0) + ->getAs() + ->getPointeeType(), + /*SpelledAsLValue=*/true), + Range); + } else { + llvm_unreachable("unexpected constructor closure!"); + } + Out << "@Z"; + return; + } Out << '@'; } else { QualType ResultType = Proto->getReturnType(); @@ -1689,7 +1738,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { } else Out << 'Y'; } -void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { +void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { // ::= A # __cdecl // ::= B # __export __cdecl // ::= C # __pascal @@ -1706,7 +1755,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { // that keyword. (It didn't actually export them, it just made them so // that they could be in a DLL and somebody from another module could call // them.) - CallingConv CC = T->getCallConv(); + switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); @@ -1720,6 +1769,9 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { case CC_X86VectorCall: Out << 'Q'; break; } } +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { + mangleCallingConvention(T->getCallConv()); +} void MicrosoftCXXNameMangler::mangleThrowSpecification( const FunctionProtoType *FT) { // ::= Z # throw(...) (default) @@ -2310,8 +2362,9 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray( } void MicrosoftMangleContextImpl::mangleCXXCatchableType( - QualType T, const CXXConstructorDecl *CD, uint32_t Size, uint32_t NVOffset, - int32_t VBPtrOffset, uint32_t VBIndex, raw_ostream &Out) { + QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size, + uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex, + raw_ostream &Out) { MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_CT"; @@ -2328,7 +2381,7 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType( llvm::SmallString<64> CopyCtorMangling; if (CD) { llvm::raw_svector_ostream Stream(CopyCtorMangling); - mangleCXXCtor(CD, Ctor_Complete, Stream); + mangleCXXCtor(CD, CT, Stream); } Mangler.getStream() << CopyCtorMangling.substr(1); @@ -2411,7 +2464,7 @@ void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) { void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, raw_ostream &Out) { - MicrosoftCXXNameMangler mangler(*this, Out); + MicrosoftCXXNameMangler mangler(*this, Out, D, Type); mangler.mangle(D); } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 0060c76..6784964 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -346,6 +346,22 @@ CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) { FTP->getExtInfo(), RequiredArgs(1)); } +const CGFunctionInfo & +CodeGenTypes::arrangeMSCopyCtorClosure(const CXXConstructorDecl *CD) { + CanQual FTP = GetFormalType(CD); + SmallVector ArgTys; + const CXXRecordDecl *RD = CD->getParent(); + ArgTys.push_back(GetThisType(Context, RD)); + ArgTys.push_back(*FTP->param_type_begin()); + if (RD->getNumVBases() > 0) + ArgTys.push_back(Context.IntTy); + CallingConv CC = Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true); + return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/true, + /*chainCall=*/false, ArgTys, + FunctionType::ExtInfo(CC), RequiredArgs::All); +} + /// Arrange a call as unto a free function, except possibly with an /// additional number of formal parameters considered required. static const CGFunctionInfo & diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h index 64c5799..f9cd383 100644 --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -82,6 +82,9 @@ inline StructorType getFromCtorType(CXXCtorType T) { return StructorType::Base; case Ctor_Comdat: llvm_unreachable("not expecting a COMDAT"); + case Ctor_CopyingClosure: + case Ctor_DefaultClosure: + llvm_unreachable("not expecting a closure"); } llvm_unreachable("not a CXXCtorType"); } @@ -261,6 +264,7 @@ public: const FunctionProtoType *type, RequiredArgs required); const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD); + const CGFunctionInfo &arrangeMSCopyCtorClosure(const CXXConstructorDecl *CD); const CGFunctionInfo &arrangeFreeFunctionType(CanQual Ty); const CGFunctionInfo &arrangeFreeFunctionType(CanQual Ty); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 7092e18..1ec37f4 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -635,6 +635,8 @@ public: return Fn; } + llvm::Function *getAddrOfCXXCopyCtorClosure(const CXXConstructorDecl *CD); + llvm::Constant *getCatchableType(QualType T, uint32_t NVOffset = 0, int32_t VBPtrOffset = -1, @@ -3220,6 +3222,103 @@ void MicrosoftCXXABI::emitCXXStructor(const CXXMethodDecl *MD, emitCXXDestructor(CGM, cast(MD), Type); } +llvm::Function * +MicrosoftCXXABI::getAddrOfCXXCopyCtorClosure(const CXXConstructorDecl *CD) { + // Calculate the mangled name. + SmallString<256> ThunkName; + llvm::raw_svector_ostream Out(ThunkName); + getMangleContext().mangleCXXCtor(CD, Ctor_CopyingClosure, Out); + Out.flush(); + + // If the thunk has been generated previously, just return it. + if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName)) + return cast(GV); + + // Create the llvm::Function. + const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSCopyCtorClosure(CD); + llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo); + const CXXRecordDecl *RD = CD->getParent(); + QualType RecordTy = getContext().getRecordType(RD); + llvm::Function *ThunkFn = llvm::Function::Create( + ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule()); + + // Start codegen. + CodeGenFunction CGF(CGM); + CGF.CurGD = GlobalDecl(CD, Ctor_Complete); + + // Build FunctionArgs. + FunctionArgList FunctionArgs; + + // A copy constructor always starts with a 'this' pointer as its first + // argument. + buildThisParam(CGF, FunctionArgs); + + // Following the 'this' pointer is a reference to the source object that we + // are copying from. + ImplicitParamDecl SrcParam( + getContext(), nullptr, SourceLocation(), &getContext().Idents.get("src"), + getContext().getLValueReferenceType(RecordTy, + /*SpelledAsLValue=*/true)); + FunctionArgs.push_back(&SrcParam); + + // Copy constructors for classes which utilize virtual bases have an + // additional parameter which indicates whether or not it is being delegated + // to by a more derived constructor. + ImplicitParamDecl IsMostDerived(getContext(), nullptr, SourceLocation(), + &getContext().Idents.get("is_most_derived"), + getContext().IntTy); + // Only add the parameter to the list if thie class has virtual bases. + if (RD->getNumVBases() > 0) + FunctionArgs.push_back(&IsMostDerived); + + // Start defining the function. + CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo, + FunctionArgs, CD->getLocation(), SourceLocation()); + EmitThisParam(CGF); + llvm::Value *This = getThisValue(CGF); + + llvm::Value *SrcVal = + CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&SrcParam), "src"); + + CallArgList Args; + + // Push the this ptr. + Args.add(RValue::get(This), CD->getThisType(getContext())); + + // Push the src ptr. + Args.add(RValue::get(SrcVal), SrcParam.getType()); + + // Add the rest of the default arguments. + std::vector ArgVec; + for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) + ArgVec.push_back(getContext().getDefaultArgExprForConstructor(CD, I)); + + CodeGenFunction::RunCleanupsScope Cleanups(CGF); + + const auto *FPT = CD->getType()->castAs(); + ConstExprIterator ArgBegin(ArgVec.data()), ArgEnd(&*ArgVec.end()); + CGF.EmitCallArgs(Args, FPT, ArgBegin, ArgEnd, CD, 1); + + // Insert any ABI-specific implicit constructor arguments. + unsigned ExtraArgs = addImplicitConstructorArgs(CGF, CD, Ctor_Complete, + /*ForVirtualBase=*/false, + /*Delegating=*/false, Args); + + // Call the destructor with our arguments. + llvm::Value *CalleeFn = CGM.getAddrOfCXXStructor(CD, StructorType::Complete); + const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall( + Args, CD, Ctor_Complete, ExtraArgs); + CGF.EmitCall(CalleeInfo, CalleeFn, ReturnValueSlot(), Args, CD); + + Cleanups.ForceCleanup(); + + // Emit the ret instruction, remove any temporary instructions created for the + // aid of CodeGen. + CGF.FinishFunction(SourceLocation()); + + return ThunkFn; +} + llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T, uint32_t NVOffset, int32_t VBPtrOffset, @@ -3229,27 +3328,43 @@ llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T, CXXRecordDecl *RD = T->getAsCXXRecordDecl(); const CXXConstructorDecl *CD = RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr; + CXXCtorType CT = Ctor_Complete; + if (CD) { + CallingConv ExpectedCallingConv = getContext().getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true); + CallingConv ActualCallingConv = + CD->getType()->getAs()->getCallConv(); + if (ExpectedCallingConv != ActualCallingConv || CD->getNumParams() != 1) + CT = Ctor_CopyingClosure; + } + uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity(); SmallString<256> MangledName; { llvm::raw_svector_ostream Out(MangledName); - getMangleContext().mangleCXXCatchableType(T, CD, Size, NVOffset, + getMangleContext().mangleCXXCatchableType(T, CD, CT, Size, NVOffset, VBPtrOffset, VBIndex, 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 + // The TypeDescriptor is used by the runtime to determine if 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 = - CD ? llvm::ConstantExpr::getBitCast( - CGM.getAddrOfCXXStructor(CD, StructorType::Complete), - CGM.Int8PtrTy) - : llvm::Constant::getNullValue(CGM.Int8PtrTy); + llvm::Constant *CopyCtor; + if (CD) { + if (CT == Ctor_CopyingClosure) + CopyCtor = getAddrOfCXXCopyCtorClosure(CD); + else + CopyCtor = CGM.getAddrOfCXXStructor(CD, StructorType::Complete); + + CopyCtor = llvm::ConstantExpr::getBitCast(CopyCtor, CGM.Int8PtrTy); + } else { + CopyCtor = llvm::Constant::getNullValue(CGM.Int8PtrTy); + } CopyCtor = getImageRelativeConstant(CopyCtor); bool IsScalar = !RD; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index b69ddf7..c62ecc7 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -782,14 +782,51 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, } } + // The MSVC ABI creates a list of all types which can catch the exception + // object. This list also references the appropriate copy constructor to call + // if the object is caught by value and has a non-trivial copy constructor. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // We are only interested in the public, unambiguous bases contained within + // the exception object. Bases which are ambiguous or otherwise + // inaccessible are not catchable types. llvm::SmallVector UnambiguousPublicSubobjects; getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); + for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { - if (CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0)) { - MarkFunctionReferenced(E->getExprLoc(), CD); - if (!CD->isTrivial()) - Context.addCopyConstructorForExceptionObject(Subobject, CD); + // Attempt to lookup the copy constructor. Various pieces of machinery + // will spring into action, like template instantiation, which means this + // cannot be a simple walk of the class's decls. Instead, we must perform + // lookup and overload resolution. + CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); + if (!CD) + continue; + + // Mark the constructor referenced as it is used by this throw expression. + MarkFunctionReferenced(E->getExprLoc(), CD); + + // Skip this copy constructor if it is trivial, we don't need to record it + // in the catchable type data. + if (CD->isTrivial()) + continue; + + // The copy constructor is non-trivial, create a mapping from this class + // type to this constructor. + // N.B. The selection of copy constructor is not sensitive to this + // particular throw-site. Lookup will be performed at the catch-site to + // ensure that the copy constructor is, in fact, accessible (via + // friendship or any other means). + Context.addCopyConstructorForExceptionObject(Subobject, CD); + + // We don't keep the instantiated default argument expressions around so + // we must rebuild them here. + for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { + // Skip any default arguments that we've already instantiated. + if (Context.getDefaultArgExprForConstructor(CD, I)) + continue; + + Expr *DefaultArg = + BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get(); + Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); } } } diff --git a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp index b4e2691..5737ce3 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 %s -fcxx-exceptions | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %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@@@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*) }, section ".xdata", comdat @@ -12,6 +12,9 @@ // CHECK-DAG: @"_CT??_R0?AUV@@@81044" = 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 }, section ".xdata", 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@@Z44", %eh.CatchableType* @"_CT??_R0?AUM@@@818", %eh.CatchableType* @"_CT??_R0?AUV@@@81044"] }, section ".xdata", 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*) }, section ".xdata", comdat +// CHECK-DAG: @"_CT??_R0?AUDefault@@@8??_ODefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor13* @"\01??_R0?AUDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Default*, %struct.Default*)* @"\01??_ODefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat +// CHECK-DAG: @"_CT??_R0?AUVariadic@@@8??_OVariadic@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor14* @"\01??_R0?AUVariadic@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Variadic*, %struct.Variadic*)* @"\01??_OVariadic@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat +// CHECK-DAG: @"_CT??_R0?AUTemplateWithDefault@@@8??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor25* @"\01??_R0?AUTemplateWithDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.TemplateWithDefault*, %struct.TemplateWithDefault*)* @"\01??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat struct N { ~N(); }; @@ -35,3 +38,52 @@ void g(const int *const *y) { // CHECK: call void @_CxxThrowException(i8* %{{.*}}, %eh.ThrowInfo* @_TIC2PAPBH) throw y; } + +struct Default { + Default(Default &, int = 42); +}; + +// CHECK-LABEL: @"\01??_ODefault@@QAEXAAU0@@Z" +// CHECK: %[[src_addr:.*]] = alloca +// CHECK: %[[this_addr:.*]] = alloca +// CHECK: store {{.*}} %src, {{.*}} %[[src_addr]], align 4 +// CHECK: store {{.*}} %this, {{.*}} %[[this_addr]], align 4 +// CHECK: %[[this:.*]] = load {{.*}} %[[this_addr]] +// CHECK: %[[src:.*]] = load {{.*}} %[[src_addr]] +// CHECK: call x86_thiscallcc {{.*}} @"\01??0Default@@QAE@AAU0@H@Z"({{.*}} %[[this]], {{.*}} %[[src]], i32 42) +// CHECK: ret void + +void h(Default &d) { + throw d; +} + +struct Variadic { + Variadic(Variadic &, ...); +}; + +void i(Variadic &v) { + throw v; +} + +// CHECK-LABEL: @"\01??_OVariadic@@QAEXAAU0@@Z" +// CHECK: %[[src_addr:.*]] = alloca +// CHECK: %[[this_addr:.*]] = alloca +// CHECK: store {{.*}} %src, {{.*}} %[[src_addr:.*]], align +// CHECK: store {{.*}} %this, {{.*}} %[[this_addr:.*]], align +// CHECK: %[[this:.*]] = load {{.*}} %[[this_addr]] +// CHECK: %[[src:.*]] = load {{.*}} %[[src_addr]] +// CHECK: %call = call {{.*}} @"\01??0Variadic@@QAA@AAU0@ZZ"({{.*}} %[[this]], {{.*}} %[[src]]) +// CHECK: ret void + +struct TemplateWithDefault { + template + static int f() { + return 0; + } + template + TemplateWithDefault(TemplateWithDefault &, T = f()); +}; + +void j(TemplateWithDefault &twd) { + throw twd; +} -- 2.7.4