I have rebased this patch on top of my refactoring patch since it
makes it quiet a bit simpler. I have attached both.
Because of some bugs in GCC there is a discussion going on
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62306 about the best way
to handle the destructor comdat. The attached patch implements the
suggestion of using a new comdat name.
On 1 September 2014 23:03, Rafael Espíndola <[email protected]> wrote:
> There are situations when clang knows that the C1 and C2 constructors
> or the D2 and D2 destructors are identical. We already optimize some
> of these cases, but cannot optimize it when the GlobalValue is
> weak_odr.
>
> The problem with weak_odr is that an old TU seeing the same code will
> have a C1 and a C2 comdat with the corresponding symbols. We cannot
> suddenly start putting the C2 symbol in the C1 comdat as we cannot
> guarantee that the linker will not pick a .o with only C1 in it.
>
> The solution implemented by GCC is to expand the ABI to have a comdat
> whose name uses a C5/D5 suffix and always has both symbols. That is
> what this patch implements.
>
> We could also use C5/D5 for linkonce_odr, but it is probably better to
> change one at a time.
>
> Cheers,
> Rafael
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 545c5ef..2cdb822 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().arrangeCXXCDtorDeclaration(ctor, getFromCtorType(ctorType));
auto *fn = cast<llvm::Function>(
GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo, true));
@@ -226,25 +226,39 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
}
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;
+CodeGenModule::getAddrOfCXXCDtor(const CXXMethodDecl *MD, CtorDtorTypes 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().arrangeCXXCDtorDeclaration(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 getAddrOfCXXCDtor(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 +284,7 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
return;
const CGFunctionInfo &fnInfo =
- getTypes().arrangeCXXDestructor(dtor, dtorType);
+ getTypes().arrangeCXXCDtorDeclaration(dtor, getFromDtorType(dtorType));
auto *fn = cast<llvm::Function>(
GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo, nullptr, true));
@@ -288,19 +302,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 getAddrOfCXXCDtor(dtor, getFromDtorType(dtorType), fnInfo, fnType,
+ DontDefer);
}
static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
@@ -361,7 +364,7 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
if (MD->isVirtual() && Type != Dtor_Base) {
// Compute the function type we're calling.
const CGFunctionInfo &FInfo =
- CGM.getTypes().arrangeCXXDestructor(DD, Dtor_Complete);
+ CGM.getTypes().arrangeCXXCDtorDeclaration(DD, CtorDtorTypes::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..47eb5b7 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 buildCDtorSignature(const CXXMethodDecl *MD, CtorDtorTypes 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..eb40ca9 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::arrangeCXXCDtorDeclaration(const CXXMethodDecl *MD,
+ CtorDtorTypes 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.buildCDtorSignature(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 arrangeCXXCDtorDeclaration(CD, getFromCtorType(GD.getCtorType()));
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
- return arrangeCXXDestructor(DD, GD.getDtorType());
+ return arrangeCXXCDtorDeclaration(DD, getFromDtorType(GD.getDtorType()));
return arrangeFunctionDeclaration(FD);
}
@@ -1029,7 +1010,7 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
const CGFunctionInfo *Info;
if (isa<CXXDestructorDecl>(MD))
- Info = &arrangeCXXDestructor(cast<CXXDestructorDecl>(MD), GD.getDtorType());
+ Info = &arrangeCXXCDtorDeclaration(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..b3e9238 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()
+ .arrangeCXXCDtorDeclaration(Ctor, getFromCtorType(CtorType)),
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index db876b1..a630a40 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().arrangeCXXCDtorDeclaration(Dtor,
+ CtorDtorTypes::Complete);
else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl))
- FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor,
- Ctor_Complete);
+ FInfo = &CGM.getTypes().arrangeCXXCDtorDeclaration(Ctor,
+ CtorDtorTypes::Complete);
else
FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 985e536..5764a0e 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 *getAddrOfCXXCDtor(const CXXMethodDecl *MD,
+ CtorDtorTypes 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..21882ba 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -56,6 +56,56 @@ class CGRecordLayout;
class CodeGenModule;
class RequiredArgs;
+enum class CtorDtorTypes {
+ Complete, // constructor or destructor
+ Base, // constructor or destructor
+ Deleting // destructor only
+};
+
+inline CXXCtorType toCXXCtorType(CtorDtorTypes T) {
+ switch (T) {
+ case CtorDtorTypes::Complete:
+ return Ctor_Complete;
+ case CtorDtorTypes::Base:
+ return Ctor_Base;
+ case CtorDtorTypes::Deleting:
+ llvm_unreachable("foo");
+ }
+}
+
+inline CtorDtorTypes getFromCtorType(CXXCtorType T) {
+ switch (T) {
+ case Ctor_Complete:
+ return CtorDtorTypes::Complete;
+ case Ctor_Base:
+ return CtorDtorTypes::Base;
+ case Ctor_CompleteAllocating:
+ llvm_unreachable("foo");
+ }
+}
+
+inline CXXDtorType toCXXDtorType(CtorDtorTypes T) {
+ switch (T) {
+ case CtorDtorTypes::Complete:
+ return Dtor_Complete;
+ case CtorDtorTypes::Base:
+ return Dtor_Base;
+ case CtorDtorTypes::Deleting:
+ return Dtor_Deleting;
+ }
+}
+
+inline CtorDtorTypes getFromDtorType(CXXDtorType T) {
+ switch (T) {
+ case Dtor_Deleting:
+ return CtorDtorTypes::Deleting;
+ case Dtor_Complete:
+ return CtorDtorTypes::Complete;
+ case Dtor_Base:
+ return CtorDtorTypes::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 &arrangeCXXCDtorDeclaration(const CXXMethodDecl *MD,
+ CtorDtorTypes 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..c2d5e1e 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 buildCDtorSignature(const CXXMethodDecl *MD, CtorDtorTypes 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::buildCDtorSignature(const CXXMethodDecl *MD,
+ CtorDtorTypes 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 == CtorDtorTypes::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().arrangeCXXCDtorDeclaration(
+ 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..d89332e 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 buildCDtorSignature(const CXXMethodDecl *MD, CtorDtorTypes 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,
- SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
-
+void
+MicrosoftCXXABI::buildCDtorSignature(const CXXMethodDecl *MD, CtorDtorTypes T,
+ SmallVectorImpl<CanQualType> &ArgTys) {
// TODO: 'for base' flag
-
- if (Type == Dtor_Deleting) {
+ if (T == CtorDtorTypes::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) {
@@ -1388,7 +1376,7 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
// by passing an implicit int parameter.
GlobalDecl GD(Dtor, Dtor_Deleting);
const CGFunctionInfo *FInfo =
- &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ &CGM.getTypes().arrangeCXXCDtorDeclaration(Dtor, CtorDtorTypes::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 2cdb822..cfbb9df 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 CtorDtorCodeGen { Emit, RAUW, Alias, COMDAT };
+}
+static CtorDtorCodeGen getCodegenToUse(CodeGenModule &CGM,
+ const CXXMethodDecl *MD) {
+ if (!CGM.getCodeGenOpts().CXXCtorDtorAliases)
+ return CtorDtorCodeGen::Emit;
+
+ // The complete constructor is equivalent to the base constructor
+ // for classes with no virtual bases.
+ if (MD->getParent()->getNumVBases())
+ return CtorDtorCodeGen::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().arrangeCXXCDtorDeclaration(ctor, getFromCtorType(ctorType));
+ if (llvm::GlobalValue::isDiscardableIfUnused(Linkage))
+ return CtorDtorCodeGen::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 CtorDtorCodeGen::RAUW;
- CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo);
+ if (llvm::GlobalValue::isWeakForLinker(Linkage))
+ return CtorDtorCodeGen::COMDAT;
- setFunctionDefinitionAttributes(ctor, fn);
- SetLLVMFunctionAttributesForDefinition(ctor, fn);
+ return CtorDtorCodeGen::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::codegenCXXCDtor(const CXXMethodDecl *MD,
+ CtorDtorTypes Type) {
+ const CGFunctionInfo &FnInfo =
+ getTypes().arrangeCXXCDtorDeclaration(MD, Type);
+ auto *Fn =
+ cast<llvm::Function>(getAddrOfCXXCDtor(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 *
@@ -259,20 +317,56 @@ 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::emitCXXCDtor(const CXXMethodDecl *MD, CtorDtorTypes Type) {
+ if (Type == CtorDtorTypes::Deleting) {
+ codegenCXXCDtor(MD, CtorDtorTypes::Deleting);
+ return;
+ }
+ assert(Type == CtorDtorTypes::Complete || Type == CtorDtorTypes::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()) {
+ codegenCXXCDtor(CD, CtorDtorTypes::Complete);
+ return;
+ }
+ } else {
+ DD = cast<CXXDestructorDecl>(MD);
+ }
+
+ CtorDtorCodeGen CompleteCG = getCodegenToUse(*this, MD);
+ if (CompleteCG == CtorDtorCodeGen::COMDAT) {
+ // Make sure both are emitted.
+ if (Type == CtorDtorTypes::Complete)
+ getAddrOfCXXCDtor(MD, CtorDtorTypes::Base);
+ else
+ getAddrOfCXXCDtor(MD, CtorDtorTypes::Complete);
+ }
+
+ if (Type == CtorDtorTypes::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 == CtorDtorCodeGen::Alias ||
+ CompleteCG == CtorDtorCodeGen::COMDAT) {
+ emitConstructorDestructorAlias(CompleteDecl, BaseDecl);
+ return;
+ }
+ if (CompleteCG == CtorDtorCodeGen::RAUW) {
+ StringRef MangledName = getMangledName(CompleteDecl);
+ auto *Aliasee = cast<llvm::GlobalValue>(GetAddrOfGlobal(BaseDecl));
+ Replacements[MangledName] = Aliasee;
+ return;
}
}
@@ -280,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 == CtorDtorTypes::Base &&
+ CompleteCG != CtorDtorCodeGen::COMDAT &&
+ !TryEmitBaseDestructorAsAlias(DD))
return;
- const CGFunctionInfo &fnInfo =
- getTypes().arrangeCXXCDtorDeclaration(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 = codegenCXXCDtor(MD, Type);
+
+ if (CompleteCG == CtorDtorCodeGen::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..faddbce 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());
+ emitCXXCDtor(CD, getFromCtorType(GD.getCtorType()));
else if (const auto *DD = dyn_cast<CXXDestructorDecl>(Method))
- EmitCXXDestructor(DD, GD.getDtorType());
+ emitCXXCDtor(DD, getFromDtorType(GD.getDtorType()));
else
EmitGlobalFunctionDefinition(GD, GV);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 5764a0e..43c0412 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,18 @@ 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 emitCXXCDtor(const CXXMethodDecl *MD, CtorDtorTypes Type);
- /// Emit a single destructor with the given type from a C++ destructor Decl.
- void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
+ llvm::Function *codegenCXXCDtor(const CXXMethodDecl *MD, CtorDtorTypes 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..d4fdd01 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,36 @@ 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
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits