On 4 September 2014 14:41, Reid Kleckner <r...@google.com> wrote: > I don't like calling arrangeCXXDtorDeclaration from ctor-related functions. > It looks like a typo. In the past I've used 'structor' as the generic term > for ctors and dtors. You can see it in the Itanium mangling code, but I > don't think it's very widely used. Does that seem like a better > nomenclature? Then we would probably have StructorType, etc.
The attached patches uses the Structor nomenclature. > I'm excited to finally have this functionality, though. :) +1 :-) Cheers, Rafael
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 545c5ef..583017c 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -213,7 +213,7 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor, } const CGFunctionInfo &fnInfo = - getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType); + getTypes().arrangeCXXStructorDeclaration(ctor, getFromCtorType(ctorType)); auto *fn = cast<llvm::Function>( GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo, true)); @@ -225,26 +225,39 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor, SetLLVMFunctionAttributesForDefinition(ctor, fn); } -llvm::GlobalValue * -CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, - CXXCtorType ctorType, - const CGFunctionInfo *fnInfo, - bool DontDefer) { - GlobalDecl GD(ctor, ctorType); - - StringRef name = getMangledName(GD); - if (llvm::GlobalValue *existing = GetGlobalValue(name)) - return existing; +llvm::GlobalValue *CodeGenModule::getAddrOfCXXStructor( + const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo, + llvm::FunctionType *FnType, bool DontDefer) { + GlobalDecl GD; + if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { + GD = GlobalDecl(CD, toCXXCtorType(Type)); + } else { + auto *DD = dyn_cast<CXXDestructorDecl>(MD); + GD = GlobalDecl(DD, toCXXDtorType(Type)); + } - if (!fnInfo) - fnInfo = &getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType); + StringRef Name = getMangledName(GD); + if (llvm::GlobalValue *Existing = GetGlobalValue(Name)) + return Existing; - llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo); - return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD, + if (!FnType) { + if (!FnInfo) + FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type); + FnType = getTypes().GetFunctionType(*FnInfo); + } + + return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FnType, GD, /*ForVTable=*/false, DontDefer)); } +llvm::GlobalValue *CodeGenModule::GetAddrOfCXXConstructor( + const CXXConstructorDecl *ctor, CXXCtorType ctorType, + const CGFunctionInfo *fnInfo, bool DontDefer) { + return getAddrOfCXXStructor(ctor, getFromCtorType(ctorType), fnInfo, nullptr, + DontDefer); +} + void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor, CXXDtorType dtorType) { // The complete destructor is equivalent to the base destructor for @@ -270,7 +283,7 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor, return; const CGFunctionInfo &fnInfo = - getTypes().arrangeCXXDestructor(dtor, dtorType); + getTypes().arrangeCXXStructorDeclaration(dtor, getFromDtorType(dtorType)); auto *fn = cast<llvm::Function>( GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo, nullptr, true)); @@ -288,19 +301,8 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, const CGFunctionInfo *fnInfo, llvm::FunctionType *fnType, bool DontDefer) { - GlobalDecl GD(dtor, dtorType); - - StringRef name = getMangledName(GD); - if (llvm::GlobalValue *existing = GetGlobalValue(name)) - return existing; - - if (!fnType) { - if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType); - fnType = getTypes().GetFunctionType(*fnInfo); - } - return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD, - /*ForVTable=*/false, - DontDefer)); + return getAddrOfCXXStructor(dtor, getFromDtorType(dtorType), fnInfo, fnType, + DontDefer); } static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF, @@ -360,8 +362,8 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall( // -O does that. But need to support -O0 as well. if (MD->isVirtual() && Type != Dtor_Base) { // Compute the function type we're calling. - const CGFunctionInfo &FInfo = - CGM.getTypes().arrangeCXXDestructor(DD, Dtor_Complete); + const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration( + DD, StructorType::Complete); llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo); return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD); } diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 39813fd..fe33179 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -241,20 +241,6 @@ public: const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) = 0; - /// Build the signature of the given constructor variant by adding - /// any required parameters. For convenience, ArgTys has been initialized - /// with the type of 'this' and ResTy has been initialized with the type of - /// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise - /// (although both may be changed by the ABI). - /// - /// If there are ever any ABIs where the implicit parameters are - /// intermixed with the formal parameters, we can address those - /// then. - virtual void BuildConstructorSignature(const CXXConstructorDecl *Ctor, - CXXCtorType T, - CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) = 0; - virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF, const CXXRecordDecl *RD); @@ -267,15 +253,11 @@ public: /// Emit constructor variants required by this ABI. virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0; - /// Build the signature of the given destructor variant by adding - /// any required parameters. For convenience, ArgTys has been initialized - /// with the type of 'this' and ResTy has been initialized with the type of - /// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise - /// (although both may be changed by the ABI). - virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType T, - CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) = 0; + /// Build the signature of the given constructor or destructor variant by + /// adding any required parameters. For convenience, ArgTys has been + /// initialized with the type of 'this'. + virtual void buildStructorSignature(const CXXMethodDecl *MD, StructorType T, + SmallVectorImpl<CanQualType> &ArgTys) = 0; /// Returns true if the given destructor type should be emitted as a linkonce /// delegating thunk, regardless of whether the dtor is defined in this TU or diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index ce16d3b..cc4a02e 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -181,30 +181,35 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) { return arrangeFreeFunctionType(prototype); } -/// Arrange the argument and result information for a declaration -/// or definition to the given constructor variant. const CGFunctionInfo & -CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D, - CXXCtorType ctorKind) { +CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD, + StructorType Type) { + SmallVector<CanQualType, 16> argTypes; - argTypes.push_back(GetThisType(Context, D->getParent())); + argTypes.push_back(GetThisType(Context, MD->getParent())); - GlobalDecl GD(D, ctorKind); - CanQualType resultType = - TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; + GlobalDecl GD; + if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { + GD = GlobalDecl(CD, toCXXCtorType(Type)); + } else { + auto *DD = dyn_cast<CXXDestructorDecl>(MD); + GD = GlobalDecl(DD, toCXXDtorType(Type)); + } - CanQual<FunctionProtoType> FTP = GetFormalType(D); + CanQual<FunctionProtoType> FTP = GetFormalType(MD); // Add the formal parameters. for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i) argTypes.push_back(FTP->getParamType(i)); - TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes); + TheCXXABI.buildStructorSignature(MD, Type, argTypes); RequiredArgs required = - (D->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All); + (MD->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All); FunctionType::ExtInfo extInfo = FTP->getExtInfo(); + CanQualType resultType = + TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required); } @@ -229,30 +234,6 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args, return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required); } -/// Arrange the argument and result information for a declaration, -/// definition, or call to the given destructor variant. It so -/// happens that all three cases produce the same information. -const CGFunctionInfo & -CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType dtorKind) { - SmallVector<CanQualType, 2> argTypes; - argTypes.push_back(GetThisType(Context, D->getParent())); - - GlobalDecl GD(D, dtorKind); - CanQualType resultType = - TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; - - TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes); - - CanQual<FunctionProtoType> FTP = GetFormalType(D); - assert(FTP->getNumParams() == 0 && "dtor with formal parameters"); - assert(FTP->isVariadic() == 0 && "dtor with formal parameters"); - - FunctionType::ExtInfo extInfo = FTP->getExtInfo(); - return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, - RequiredArgs::All); -} - /// Arrange the argument and result information for the declaration or /// definition of the given function. const CGFunctionInfo & @@ -324,10 +305,10 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) { const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) - return arrangeCXXConstructorDeclaration(CD, GD.getCtorType()); + return arrangeCXXStructorDeclaration(CD, getFromCtorType(GD.getCtorType())); if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) - return arrangeCXXDestructor(DD, GD.getDtorType()); + return arrangeCXXStructorDeclaration(DD, getFromDtorType(GD.getDtorType())); return arrangeFunctionDeclaration(FD); } @@ -1029,7 +1010,8 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { const CGFunctionInfo *Info; if (isa<CXXDestructorDecl>(MD)) - Info = &arrangeCXXDestructor(cast<CXXDestructorDecl>(MD), GD.getDtorType()); + Info = + &arrangeCXXStructorDeclaration(MD, getFromDtorType(GD.getDtorType())); else Info = &arrangeCXXMethodDeclaration(MD); return GetFunctionType(*Info); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 5a033de..3277b41 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1758,7 +1758,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, } llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType); - EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType), + EmitCall(CGM.getTypes() + .arrangeCXXStructorDeclaration(Ctor, getFromCtorType(CtorType)), Callee, ReturnValueSlot(), DelegateArgs, Ctor); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index db876b1..937a043 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -170,11 +170,11 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, const CXXMethodDecl *CalleeDecl = DevirtualizedMethod ? DevirtualizedMethod : MD; const CGFunctionInfo *FInfo = nullptr; if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl)) - FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor, - Dtor_Complete); + FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration( + Dtor, StructorType::Complete); else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl)) - FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, - Ctor_Complete); + FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration( + Ctor, StructorType::Complete); else FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 985e536..452553f 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -803,6 +803,13 @@ public: QualType getObjCFastEnumerationStateType(); /// Return the address of the constructor of the given type. + + llvm::GlobalValue * + getAddrOfCXXStructor(const CXXMethodDecl *MD, StructorType Type, + const CGFunctionInfo *FnInfo = nullptr, + llvm::FunctionType *FnType = nullptr, + bool DontDefer = false); + llvm::GlobalValue * GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, CXXCtorType ctorType, const CGFunctionInfo *fnInfo = nullptr, diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index b1c9dad..088fb69 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -56,6 +56,56 @@ class CGRecordLayout; class CodeGenModule; class RequiredArgs; +enum class StructorType { + Complete, // constructor or destructor + Base, // constructor or destructor + Deleting // destructor only +}; + +inline CXXCtorType toCXXCtorType(StructorType T) { + switch (T) { + case StructorType::Complete: + return Ctor_Complete; + case StructorType::Base: + return Ctor_Base; + case StructorType::Deleting: + llvm_unreachable("foo"); + } +} + +inline StructorType getFromCtorType(CXXCtorType T) { + switch (T) { + case Ctor_Complete: + return StructorType::Complete; + case Ctor_Base: + return StructorType::Base; + case Ctor_CompleteAllocating: + llvm_unreachable("foo"); + } +} + +inline CXXDtorType toCXXDtorType(StructorType T) { + switch (T) { + case StructorType::Complete: + return Dtor_Complete; + case StructorType::Base: + return Dtor_Base; + case StructorType::Deleting: + return Dtor_Deleting; + } +} + +inline StructorType getFromDtorType(CXXDtorType T) { + switch (T) { + case Dtor_Deleting: + return StructorType::Deleting; + case Dtor_Complete: + return StructorType::Complete; + case Dtor_Base: + return StructorType::Base; + } +} + /// CodeGenTypes - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. class CodeGenTypes { @@ -185,16 +235,12 @@ public: QualType receiverType); const CGFunctionInfo &arrangeCXXMethodDeclaration(const CXXMethodDecl *MD); - const CGFunctionInfo &arrangeCXXConstructorDeclaration( - const CXXConstructorDecl *D, - CXXCtorType Type); + const CGFunctionInfo &arrangeCXXStructorDeclaration(const CXXMethodDecl *MD, + StructorType Type); const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args, const CXXConstructorDecl *D, CXXCtorType CtorKind, unsigned ExtraArgs); - const CGFunctionInfo &arrangeCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType Type); - const CGFunctionInfo &arrangeFreeFunctionCall(const CallArgList &Args, const FunctionType *Ty); const CGFunctionInfo &arrangeFreeFunctionCall(QualType ResTy, diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index f861af3..60b6ecd 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -138,15 +138,10 @@ public: const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) override; - void BuildConstructorSignature(const CXXConstructorDecl *Ctor, - CXXCtorType T, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) override; - void EmitCXXConstructors(const CXXConstructorDecl *D) override; - void BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType T, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) override; + void buildStructorSignature(const CXXMethodDecl *MD, StructorType T, + SmallVectorImpl<CanQualType> &ArgTys) override; bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, CXXDtorType DT) const override { @@ -1066,23 +1061,6 @@ ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, return VBaseOffset; } -/// The generic ABI passes 'this', plus a VTT if it's initializing a -/// base subobject. -void -ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, - CXXCtorType Type, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) { - ASTContext &Context = getContext(); - - // All parameters are already in place except VTT, which goes after 'this'. - // These are Clang types, so we don't need to worry about sret yet. - - // Check if we need to add a VTT parameter (which has type void **). - if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0) - ArgTys.insert(ArgTys.begin() + 1, - Context.getPointerType(Context.VoidPtrTy)); -} - void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) { // Just make sure we're in sync with TargetCXXABI. assert(CGM.getTarget().getCXXABI().hasConstructorVariants()); @@ -1099,20 +1077,18 @@ void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) { } } -/// The generic ABI passes 'this', plus a VTT if it's destroying a -/// base subobject. -void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType Type, - CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) { +void +ItaniumCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T, + SmallVectorImpl<CanQualType> &ArgTys) { ASTContext &Context = getContext(); - // 'this' parameter is already there, as well as 'this' return if - // HasThisReturn(GlobalDecl(Dtor, Type)) is true + // All parameters are already in place except VTT, which goes after 'this'. + // These are Clang types, so we don't need to worry about sret yet. // Check if we need to add a VTT parameter (which has type void **). - if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0) - ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + if (T == StructorType::Base && MD->getParent()->getNumVBases() != 0) + ArgTys.insert(ArgTys.begin() + 1, + Context.getPointerType(Context.VoidPtrTy)); } void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) { @@ -1346,8 +1322,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, assert(CE == nullptr || CE->arg_begin() == CE->arg_end()); assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete); - const CGFunctionInfo *FInfo - = &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType); + const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration( + Dtor, getFromDtorType(DtorType)); llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); llvm::Value *Callee = getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 134f0b7..b3074de 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -89,10 +89,6 @@ public: const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) override; - void BuildConstructorSignature(const CXXConstructorDecl *Ctor, - CXXCtorType Type, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) override; - llvm::BasicBlock * EmitCtorCompleteObjectHandler(CodeGenFunction &CGF, const CXXRecordDecl *RD) override; @@ -134,10 +130,8 @@ public: // lacks a definition for the destructor, non-base destructors must always // delegate to or alias the base destructor. - void BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType Type, - CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) override; + void buildStructorSignature(const CXXMethodDecl *MD, StructorType T, + SmallVectorImpl<CanQualType> &ArgTys) override; /// Non-base dtors should be emitted as delegating thunks in this ABI. bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, @@ -785,23 +779,6 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { return false; } -void MicrosoftCXXABI::BuildConstructorSignature( - const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) { - - // All parameters are already in place except is_most_derived, which goes - // after 'this' if it's variadic and last if it's not. - - const CXXRecordDecl *Class = Ctor->getParent(); - const FunctionProtoType *FPT = Ctor->getType()->castAs<FunctionProtoType>(); - if (Class->getNumVBases()) { - if (FPT->isVariadic()) - ArgTys.insert(ArgTys.begin() + 1, CGM.getContext().IntTy); - else - ArgTys.push_back(CGM.getContext().IntTy); - } -} - llvm::BasicBlock * MicrosoftCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF, const CXXRecordDecl *RD) { @@ -910,18 +887,29 @@ void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF, } } -void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType Type, - CanQualType &ResTy, +void +MicrosoftCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T, SmallVectorImpl<CanQualType> &ArgTys) { - // 'this' is already in place - // TODO: 'for base' flag - - if (Type == Dtor_Deleting) { + if (T == StructorType::Deleting) { // The scalar deleting destructor takes an implicit int parameter. ArgTys.push_back(CGM.getContext().IntTy); } + auto *CD = dyn_cast<CXXConstructorDecl>(MD); + if (!CD) + return; + + // All parameters are already in place except is_most_derived, which goes + // after 'this' if it's variadic and last if it's not. + + const CXXRecordDecl *Class = CD->getParent(); + const FunctionProtoType *FPT = CD->getType()->castAs<FunctionProtoType>(); + if (Class->getNumVBases()) { + if (FPT->isVariadic()) + ArgTys.insert(ArgTys.begin() + 1, CGM.getContext().IntTy); + else + ArgTys.push_back(CGM.getContext().IntTy); + } } void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) { @@ -1387,8 +1375,8 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, // We have only one destructor in the vftable but can get both behaviors // by passing an implicit int parameter. GlobalDecl GD(Dtor, Dtor_Deleting); - const CGFunctionInfo *FInfo = - &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting); + const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration( + Dtor, StructorType::Deleting); llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); llvm::Value *Callee = getVirtualFunctionPointer(CGF, GD, This, Ty);
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index a8d1199..9423582 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -111,6 +111,8 @@ public: raw_ostream &) = 0; virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &) = 0; + virtual void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &); + virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &); virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0; void mangleGlobalBlock(const BlockDecl *BD, diff --git a/include/clang/Basic/ABI.h b/include/clang/Basic/ABI.h index a3aad4b..fcb6b21 100644 --- a/include/clang/Basic/ABI.h +++ b/include/clang/Basic/ABI.h @@ -27,6 +27,8 @@ enum CXXCtorType { Ctor_CompleteAllocating ///< Complete object allocating ctor }; +enum CXXCtorComdatType { Ctor_Comdat = Ctor_CompleteAllocating + 1 }; + /// \brief C++ destructor types. enum CXXDtorType { Dtor_Deleting, ///< Deleting dtor @@ -34,6 +36,8 @@ enum CXXDtorType { Dtor_Base ///< Base object dtor }; +enum CXXDtorComdatType { Dtor_Comdat = Dtor_Base + 1 }; + /// \brief A return adjustment. struct ReturnAdjustment { /// \brief The non-virtual adjustment from the derived object to its diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 486fab3..3698508 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -149,7 +149,8 @@ public: raw_ostream &) override; void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &) override; - + void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) override; + void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) override; void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) override; void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override; void mangleDynamicAtExitDestructor(const VarDecl *D, @@ -261,13 +262,13 @@ public: !isa<CXXConstructorDecl>(D))); } CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_, - const CXXConstructorDecl *D, CXXCtorType Type) - : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } + const CXXConstructorDecl *D, unsigned Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) {} CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_, - const CXXDestructorDecl *D, CXXDtorType Type) - : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } + const CXXDestructorDecl *D, unsigned Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) {} #if MANGLE_CHECKER ~CXXNameMangler() { @@ -374,8 +375,8 @@ private: DeclarationName name, unsigned knownArity); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); - void mangleCXXCtorType(CXXCtorType T); - void mangleCXXDtorType(CXXDtorType T); + void mangleCXXCtorType(unsigned T); + void mangleCXXDtorType(unsigned T); void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs); void mangleTemplateArgs(const TemplateArgument *TemplateArgs, @@ -1188,7 +1189,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, if (ND == Structor) // If the named decl is the C++ constructor we're mangling, use the type // we were given. - mangleCXXCtorType(static_cast<CXXCtorType>(StructorType)); + mangleCXXCtorType(StructorType); else // Otherwise, use the complete constructor name. This is relevant if a // class with a constructor is declared within a constructor. @@ -1199,7 +1200,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, if (ND == Structor) // If the named decl is the C++ destructor we're mangling, use the type we // were given. - mangleCXXDtorType(static_cast<CXXDtorType>(StructorType)); + mangleCXXDtorType(StructorType); else // Otherwise, use the complete destructor name. This is relevant if a // class with a destructor is declared within a destructor. @@ -3246,12 +3247,15 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { Out << '_'; } -void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { +void CXXNameMangler::mangleCXXCtorType(unsigned T) { // <ctor-dtor-name> ::= C1 # complete object constructor // ::= C2 # base object constructor // ::= C3 # complete object allocating constructor // + // In addition, C5 is a comdat name with C1 and C2 in it. switch (T) { + default: + llvm_unreachable("unsupported type"); case Ctor_Complete: Out << "C1"; break; @@ -3261,15 +3265,21 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { case Ctor_CompleteAllocating: Out << "C3"; break; + case Ctor_Comdat: + Out << "C5"; + break; } } -void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { +void CXXNameMangler::mangleCXXDtorType(unsigned T) { // <ctor-dtor-name> ::= D0 # deleting destructor // ::= D1 # complete object destructor // ::= D2 # base object destructor // + // In addition, C5 is a comdat name with C1 and C2 in it. switch (T) { + default: + llvm_unreachable("unsupported type"); case Dtor_Deleting: Out << "D0"; break; @@ -3279,6 +3289,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { case Dtor_Base: Out << "D2"; break; + case Dtor_Comdat: + Out << "D6"; + break; } } @@ -3689,6 +3702,18 @@ void ItaniumMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D, Mangler.mangle(D); } +void ItaniumMangleContextImpl::mangleCXXCtorComdat(const CXXConstructorDecl *D, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Ctor_Comdat); + Mangler.mangle(D); +} + +void ItaniumMangleContextImpl::mangleCXXDtorComdat(const CXXDestructorDecl *D, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Dtor_Comdat); + Mangler.mangle(D); +} + void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &Out) { diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index fdc00e3..bbc72a4 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -90,6 +90,16 @@ static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context, } } +void MangleContext::mangleCXXCtorComdat(const CXXConstructorDecl *D, + raw_ostream &Out) { + llvm_unreachable("Should not be used by this mangling"); +} + +void MangleContext::mangleCXXDtorComdat(const CXXDestructorDecl *D, + raw_ostream &Out) { + llvm_unreachable("Should not be used by this mangling"); +} + bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { const ASTContext &ASTContext = getASTContext(); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 583017c..94801c6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -102,16 +102,14 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { return true; return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), - GlobalDecl(BaseD, Dtor_Base), - false); + GlobalDecl(BaseD, Dtor_Base)); } /// Try to emit a definition as a global alias for another definition. /// If \p InEveryTU is true, we know that an equivalent alias can be produced /// in every translation unit. bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, - GlobalDecl TargetDecl, - bool InEveryTU) { + GlobalDecl TargetDecl) { if (!getCodeGenOpts().CXXCtorDtorAliases) return true; @@ -160,13 +158,11 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, return false; } - if (!InEveryTU) { - /// If we don't have a definition for the destructor yet, don't - /// emit. We can't emit aliases to declarations; that's just not - /// how aliases work. - if (Ref->isDeclaration()) - return true; - } + /// If we don't have a definition for the destructor yet, don't + /// emit. We can't emit aliases to declarations; that's just not + /// how aliases work. + if (Ref->isDeclaration()) + return true; // Don't create an alias to a linker weak symbol. This avoids producing // different COMDATs in different TUs. Another option would be to @@ -196,33 +192,95 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, return false; } -void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor, - CXXCtorType ctorType) { - if (!getTarget().getCXXABI().hasConstructorVariants()) { - // If there are no constructor variants, always emit the complete destructor. - ctorType = Ctor_Complete; - } else if (!ctor->getParent()->getNumVBases() && - (ctorType == Ctor_Complete || ctorType == Ctor_Base)) { - // The complete constructor is equivalent to the base constructor - // for classes with no virtual bases. Try to emit it as an alias. - bool ProducedAlias = - !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete), - GlobalDecl(ctor, Ctor_Base), true); - if (ctorType == Ctor_Complete && ProducedAlias) - return; +// Find out how to codegen the complete destructor and constructor +namespace { +enum class StructorCodegen { Emit, RAUW, Alias, COMDAT }; +} +static StructorCodegen getCodegenToUse(CodeGenModule &CGM, + const CXXMethodDecl *MD) { + if (!CGM.getCodeGenOpts().CXXCtorDtorAliases) + return StructorCodegen::Emit; + + // The complete constructor is equivalent to the base constructor + // for classes with no virtual bases. + if (MD->getParent()->getNumVBases()) + return StructorCodegen::Emit; + + GlobalDecl AliasDecl; + if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) { + AliasDecl = GlobalDecl(DD, Dtor_Complete); + } else { + const auto *CD = cast<CXXConstructorDecl>(MD); + AliasDecl = GlobalDecl(CD, Ctor_Complete); } + llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl); - const CGFunctionInfo &fnInfo = - getTypes().arrangeCXXStructorDeclaration(ctor, getFromCtorType(ctorType)); + if (llvm::GlobalValue::isDiscardableIfUnused(Linkage)) + return StructorCodegen::RAUW; - auto *fn = cast<llvm::Function>( - GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo, true)); - setFunctionLinkage(GlobalDecl(ctor, ctorType), fn); + // FIXME: Should we allow available_externally aliases? + if (!llvm::GlobalAlias::isValidLinkage(Linkage)) + return StructorCodegen::RAUW; - CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo); + if (llvm::GlobalValue::isWeakForLinker(Linkage)) + return StructorCodegen::COMDAT; - setFunctionDefinitionAttributes(ctor, fn); - SetLLVMFunctionAttributesForDefinition(ctor, fn); + return StructorCodegen::Alias; +} + +void CodeGenModule::emitConstructorDestructorAlias(GlobalDecl AliasDecl, + GlobalDecl TargetDecl) { + llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl); + + StringRef MangledName = getMangledName(AliasDecl); + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + if (Entry && !Entry->isDeclaration()) + return; + + auto *Aliasee = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl)); + llvm::PointerType *AliasType = Aliasee->getType(); + + // Create the alias with no name. + auto *Alias = llvm::GlobalAlias::create(AliasType->getElementType(), 0, + Linkage, "", Aliasee, &getModule()); + + // Switch any previous uses to the alias. + if (Entry) { + assert(Entry->getType() == AliasType && + "declaration exists with different type"); + Alias->takeName(Entry); + Entry->replaceAllUsesWith(Alias); + Entry->eraseFromParent(); + } else { + Alias->setName(MangledName); + } + + // Finally, set up the alias with its proper name and attributes. + SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias); +} + +llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD, + StructorType Type) { + const CGFunctionInfo &FnInfo = + getTypes().arrangeCXXStructorDeclaration(MD, Type); + auto *Fn = cast<llvm::Function>( + getAddrOfCXXStructor(MD, Type, &FnInfo, nullptr, true)); + if (!Fn->isDeclaration()) + return Fn; + + GlobalDecl GD; + if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) { + GD = GlobalDecl(DD, toCXXDtorType(Type)); + } else { + const auto *CD = cast<CXXConstructorDecl>(MD); + GD = GlobalDecl(CD, toCXXCtorType(Type)); + } + + setFunctionLinkage(GD, Fn); + CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo); + setFunctionDefinitionAttributes(MD, Fn); + SetLLVMFunctionAttributesForDefinition(MD, Fn); + return Fn; } llvm::GlobalValue *CodeGenModule::getAddrOfCXXStructor( @@ -258,20 +316,57 @@ llvm::GlobalValue *CodeGenModule::GetAddrOfCXXConstructor( DontDefer); } -void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor, - CXXDtorType dtorType) { - // The complete destructor is equivalent to the base destructor for - // classes with no virtual bases, so try to emit it as an alias. - if (!dtor->getParent()->getNumVBases() && - (dtorType == Dtor_Complete || dtorType == Dtor_Base)) { - bool ProducedAlias = - !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete), - GlobalDecl(dtor, Dtor_Base), true); - if (ProducedAlias) { - if (dtorType == Dtor_Complete) - return; - if (dtor->isVirtual()) - getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete)); +void CodeGenModule::emitCXXStructor(const CXXMethodDecl *MD, + StructorType Type) { + if (Type == StructorType::Deleting) { + codegenCXXStructor(MD, StructorType::Deleting); + return; + } + assert(Type == StructorType::Complete || Type == StructorType::Base); + + auto *CD = dyn_cast<CXXConstructorDecl>(MD); + const CXXDestructorDecl *DD = nullptr; + if (CD) { + // If there are no constructor variants, always emit the complete + // destructor. + if (!getTarget().getCXXABI().hasConstructorVariants()) { + codegenCXXStructor(CD, StructorType::Complete); + return; + } + } else { + DD = cast<CXXDestructorDecl>(MD); + } + + StructorCodegen CompleteCG = getCodegenToUse(*this, MD); + if (CompleteCG == StructorCodegen::COMDAT) { + // Make sure both are emitted. + if (Type == StructorType::Complete) + getAddrOfCXXStructor(MD, StructorType::Base); + else + getAddrOfCXXStructor(MD, StructorType::Complete); + } + + if (Type == StructorType::Complete) { + GlobalDecl CompleteDecl; + GlobalDecl BaseDecl; + if (CD) { + CompleteDecl = GlobalDecl(CD, Ctor_Complete); + BaseDecl = GlobalDecl(CD, Ctor_Base); + } else { + CompleteDecl = GlobalDecl(DD, Dtor_Complete); + BaseDecl = GlobalDecl(DD, Dtor_Base); + } + + if (CompleteCG == StructorCodegen::Alias || + CompleteCG == StructorCodegen::COMDAT) { + emitConstructorDestructorAlias(CompleteDecl, BaseDecl); + return; + } + if (CompleteCG == StructorCodegen::RAUW) { + StringRef MangledName = getMangledName(CompleteDecl); + auto *Aliasee = cast<llvm::GlobalValue>(GetAddrOfGlobal(BaseDecl)); + Replacements[MangledName] = Aliasee; + return; } } @@ -279,20 +374,24 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor, // base class if there is exactly one non-virtual base class with a // non-trivial destructor, there are no fields with a non-trivial // destructor, and the body of the destructor is trivial. - if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor)) + // FIXME: not if COMDAT... + if (DD && Type == StructorType::Base && + CompleteCG != StructorCodegen::COMDAT && + !TryEmitBaseDestructorAsAlias(DD)) return; - const CGFunctionInfo &fnInfo = - getTypes().arrangeCXXStructorDeclaration(dtor, getFromDtorType(dtorType)); - - auto *fn = cast<llvm::Function>( - GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo, nullptr, true)); - setFunctionLinkage(GlobalDecl(dtor, dtorType), fn); - - CodeGenFunction(*this).GenerateCode(GlobalDecl(dtor, dtorType), fn, fnInfo); - - setFunctionDefinitionAttributes(dtor, fn); - SetLLVMFunctionAttributesForDefinition(dtor, fn); + llvm::Function *Fn = codegenCXXStructor(MD, Type); + + if (CompleteCG == StructorCodegen::COMDAT) { + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + if (DD) + ABI->getMangleContext().mangleCXXDtorComdat(DD, Out); + else + ABI->getMangleContext().mangleCXXCtorComdat(CD, Out); + llvm::Comdat *C = TheModule.getOrInsertComdat(Out.str()); + Fn->setComdat(C); + } } llvm::GlobalValue * diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index aaadbd4..8ef3baa 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1066,7 +1066,7 @@ void CodeGenModule::EmitDeferred() { // Stop if we're out of both deferred v-tables and deferred declarations. if (DeferredDeclsToEmit.empty()) break; - DeferredGlobal &G = DeferredDeclsToEmit.back(); + const DeferredGlobal &G = DeferredDeclsToEmit.back(); GlobalDecl D = G.GD; llvm::GlobalValue *GV = G.GV; DeferredDeclsToEmit.pop_back(); @@ -1404,9 +1404,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { // Make sure to emit the definition(s) before we emit the thunks. // This is necessary for the generation of certain thunks. if (const auto *CD = dyn_cast<CXXConstructorDecl>(Method)) - EmitCXXConstructor(CD, GD.getCtorType()); + emitCXXStructor(CD, getFromCtorType(GD.getCtorType())); else if (const auto *DD = dyn_cast<CXXDestructorDecl>(Method)) - EmitCXXDestructor(DD, GD.getDtorType()); + emitCXXStructor(DD, getFromDtorType(GD.getDtorType())); else EmitGlobalFunctionDefinition(GD, GV); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 452553f..e99c483 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -320,7 +320,7 @@ class CodeGenModule : public CodeGenTypeCache { /// referenced. These get code generated when the module is done. struct DeferredGlobal { DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {} - llvm::AssertingVH<llvm::GlobalValue> GV; + llvm::TrackingVH<llvm::GlobalValue> GV; GlobalDecl GD; }; std::vector<DeferredGlobal> DeferredDeclsToEmit; @@ -1097,19 +1097,19 @@ private: // C++ related functions. - bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target, - bool InEveryTU); + bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); + void emitConstructorDestructorAlias(GlobalDecl Alias, GlobalDecl Target); + void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); void CompleteDIClassType(const CXXMethodDecl* D); - /// Emit a single constructor with the given type from a C++ constructor Decl. - void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type); + void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type); - /// Emit a single destructor with the given type from a C++ destructor Decl. - void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); + llvm::Function *codegenCXXStructor(const CXXMethodDecl *MD, + StructorType Type); /// \brief Emit the function that initializes C++ thread_local variables. void EmitCXXThreadLocalInitFunc(); diff --git a/test/CodeGenCXX/ctor-dtor-alias.cpp b/test/CodeGenCXX/ctor-dtor-alias.cpp index 8be5494..40388c7 100644 --- a/test/CodeGenCXX/ctor-dtor-alias.cpp +++ b/test/CodeGenCXX/ctor-dtor-alias.cpp @@ -6,18 +6,23 @@ // RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK4 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK5 --input-file=%t %s +// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t %s namespace test1 { -// test that we don't produce an alias when the destructor is weak_odr. The -// reason to avoid it that another TU might have no explicit template -// instantiation definition or declaration, causing it to to output only -// one of the destructors as linkonce_odr, producing a different comdat. - -// CHECK1: define weak_odr void @_ZN5test16foobarIvEC2Ev -// CHECK1: define weak_odr void @_ZN5test16foobarIvEC1Ev - -template <typename T> struct foobar { +// Test that we produce the apropriate comdats when creating aliases to +// weak_odr constructors and destructors. + +// CHECK1: @_ZN5test16foobarIvEC1Ev = weak_odr alias void {{.*}} @_ZN5test16foobarIvEC2Ev +// CHECK1: @_ZN5test16foobarIvED1Ev = weak_odr alias void (%"struct.test1::foobar"*)* @_ZN5test16foobarIvED2Ev +// CHECK1: define weak_odr void @_ZN5test16foobarIvEC2Ev({{.*}} comdat $_ZN5test16foobarIvEC5Ev +// CHECK1: define weak_odr void @_ZN5test16foobarIvED2Ev({{.*}} comdat $_ZN5test16foobarIvED6Ev +// CHECK1: define weak_odr void @_ZN5test16foobarIvED0Ev( +// CHECK1-NOT: comdat + +template <typename T> +struct foobar { foobar() {} + virtual ~foobar() {} }; template struct foobar<void>; @@ -187,3 +192,38 @@ void fn1() { new C; } + +namespace test10 { +// Test that if a destructor is in a comdat, we don't try to emit is as an +// alias to a base class destructor. +struct bar { + ~bar(); +}; +bar::~bar() { +} +} // closing the namespace causes ~bar to be sent to CodeGen +namespace test10 { +template <typename T> +struct foo : public bar { + ~foo(); +}; +template <typename T> +foo<T>::~foo() {} +template class foo<int>; +// CHECK5: define weak_odr void @_ZN6test103fooIiED2Ev({{.*}} comdat $_ZN6test103fooIiED6Ev +} + +namespace test11 { +// Test that when we don't have to worry about COMDATs we produce an alias +// from complate to base and from base to base class base. +struct bar { + ~bar(); +}; +bar::~bar() {} +struct foo : public bar { + ~foo(); +}; +foo::~foo() {} +// CHECK6: @_ZN6test113fooD2Ev = alias {{.*}} @_ZN6test113barD2Ev +// CHECK6: @_ZN6test113fooD1Ev = alias {{.*}} @_ZN6test113fooD2Ev +} diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 0bfc8ec..bc9a683 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -204,18 +204,14 @@ namespace test3 { // CHECK4: call void @_ZN5test312_GLOBAL__N_11DD0Ev( // CHECK4: ret void - // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( - // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8 - // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev( - // CHECK4: ret void + // CHECK4-LABEL: declare void @_ZN5test31BD2Ev( + // CHECK4-LABEL: declare void @_ZN5test31AD2Ev( // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::(anonymous namespace)::C"* %this) unnamed_addr // CHECK4: invoke void @_ZN5test31BD2Ev( // CHECK4: call void @_ZN5test31AD2Ev( // CHECK4: ret void - // CHECK4: declare void @_ZN5test31BD2Ev( - // CHECK4: declare void @_ZN5test31AD2Ev( // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::(anonymous namespace)::C"* %this) unnamed_addr // CHECK4: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev( @@ -226,6 +222,11 @@ namespace test3 { // CHECK4: call void @_ZdlPv({{.*}}) [[NUW]] // CHECK4: resume { i8*, i32 } + // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( + // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev( + // CHECK4: ret void + // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8 // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD0Ev( diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp index 3e7fa82..f0e3dc5 100644 --- a/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -17,8 +17,8 @@ struct B : A { // CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev // (aliases from C) -// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev // CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev +// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev // Base dtor: actually calls A's base dtor. // CHECK-LABEL: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits