summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp400
1 files changed, 308 insertions, 92 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
index d7e61f0..f2ffabc 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -106,8 +106,11 @@ public:
llvm::Value *Addr,
const MemberPointerType *MPT) override;
- llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value *ptr,
- QualType type) override;
+ void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE,
+ llvm::Value *Ptr, QualType ElementType,
+ const CXXDestructorDecl *Dtor) override;
+
+ void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
void EmitFundamentalRTTIDescriptor(QualType Type);
void EmitFundamentalRTTIDescriptors();
@@ -138,15 +141,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 {
@@ -192,10 +190,11 @@ public:
llvm::Value *This,
llvm::Type *Ty) override;
- void EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType, SourceLocation CallLoc,
- llvm::Value *This) override;
+ llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ llvm::Value *This,
+ const CXXMemberCallExpr *CE) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
@@ -213,6 +212,12 @@ public:
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
const ReturnAdjustment &RA) override;
+ size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
+ FunctionArgList &Args) const override {
+ assert(!Args.empty() && "expected the arglist to not be empty!");
+ return Args.size() - 1;
+ }
+
StringRef GetPureVirtualCallName() override { return "__cxa_pure_virtual"; }
StringRef GetDeletedVirtualCallName() override
{ return "__cxa_deleted_virtual"; }
@@ -234,10 +239,15 @@ public:
llvm::Constant *dtor, llvm::Constant *addr) override;
llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD,
- llvm::GlobalVariable *Var);
+ llvm::Value *Val);
void EmitThreadLocalInitFuncs(
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc) override;
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals,
+ ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override;
+
+ bool usesThreadWrapperFunction() const override { return true; }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
QualType LValType) override;
@@ -273,6 +283,8 @@ public:
classifyRTTIUniqueness(QualType CanTy,
llvm::GlobalValue::LinkageTypes Linkage) const;
friend class ItaniumRTTIBuilder;
+
+ void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -348,7 +360,7 @@ llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
return CGM.PtrDiffTy;
- return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, NULL);
+ return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, nullptr);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -839,21 +851,56 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
/// The Itanium ABI always places an offset to the complete object
/// at entry -2 in the vtable.
-llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
- llvm::Value *ptr,
- QualType type) {
- // Grab the vtable pointer as an intptr_t*.
- llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo());
-
- // Track back to entry -2 and pull out the offset there.
- llvm::Value *offsetPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr");
- llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr);
- offset->setAlignment(CGF.PointerAlignInBytes);
+void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr,
+ QualType ElementType,
+ const CXXDestructorDecl *Dtor) {
+ bool UseGlobalDelete = DE->isGlobalDelete();
+ if (UseGlobalDelete) {
+ // Derive the complete-object pointer, which is what we need
+ // to pass to the deallocation function.
+
+ // Grab the vtable pointer as an intptr_t*.
+ llvm::Value *VTable = CGF.GetVTablePtr(Ptr, CGF.IntPtrTy->getPointerTo());
+
+ // Track back to entry -2 and pull out the offset there.
+ llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
+ VTable, -2, "complete-offset.ptr");
+ llvm::LoadInst *Offset = CGF.Builder.CreateLoad(OffsetPtr);
+ Offset->setAlignment(CGF.PointerAlignInBytes);
+
+ // Apply the offset.
+ llvm::Value *CompletePtr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy);
+ CompletePtr = CGF.Builder.CreateInBoundsGEP(CompletePtr, Offset);
+
+ // If we're supposed to call the global delete, make sure we do so
+ // even if the destructor throws.
+ CGF.pushCallObjectDeleteCleanup(DE->getOperatorDelete(), CompletePtr,
+ ElementType);
+ }
- // Apply the offset.
- ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
- return CGF.Builder.CreateInBoundsGEP(ptr, offset);
+ // FIXME: Provide a source location here even though there's no
+ // CXXMemberCallExpr for dtor call.
+ CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+ EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
+
+ if (UseGlobalDelete)
+ CGF.PopCleanupBlock();
+}
+
+void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
+ // void __cxa_rethrow();
+
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
+
+ llvm::Constant *Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
+
+ if (isNoReturn)
+ CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, None);
+ else
+ CGF.EmitRuntimeCallOrInvoke(Fn);
}
static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
@@ -1066,23 +1113,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());
@@ -1092,27 +1122,25 @@ void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
CGM.EmitGlobal(GlobalDecl(D, Ctor_Base));
// The constructor used for constructing this as a complete class;
- // constucts the virtual bases, then calls the base constructor.
+ // constructs the virtual bases, then calls the base constructor.
if (!D->getParent()->isAbstract()) {
// We don't need to emit the complete ctor if the class is abstract.
CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
}
}
-/// 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) {
@@ -1201,11 +1229,10 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
Callee = CGF.BuildAppleKextVirtualDestructorCall(DD, Type, DD->getParent());
if (!Callee)
- Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+ Callee = CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type));
- // FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, VTTTy, nullptr, nullptr);
+ CGF.EmitCXXMemberOrOperatorCall(DD, Callee, ReturnValueSlot(), This, VTT,
+ VTTTy, nullptr);
}
void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -1232,6 +1259,12 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
// Set the right visibility.
CGM.setGlobalVisibility(VTable, RD);
+ // Use pointer alignment for the vtable. Otherwise we would align them based
+ // on the size of the initializer which doesn't make sense as only single
+ // values are read.
+ unsigned PAlign = CGM.getTarget().getPointerAlign(0);
+ VTable->setAlignment(getContext().toCharUnitsFromBits(PAlign).getQuantity());
+
// If this is the magic class __cxxabiv1::__fundamental_type_info,
// we will emit the typeinfo for the fundamental types. This is the
// same behaviour as GCC.
@@ -1339,22 +1372,21 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
return CGF.Builder.CreateLoad(VFuncPtr);
}
-void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- llvm::Value *This) {
+llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
+ CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
+ llvm::Value *This, const CXXMemberCallExpr *CE) {
+ 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);
- CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
- /*ImplicitParam=*/nullptr, QualType(), nullptr,
- nullptr);
+ CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(), This,
+ /*ImplicitParam=*/nullptr, QualType(), CE);
+ return nullptr;
}
void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
@@ -1473,10 +1505,20 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
CookieOffset.getQuantity());
// Write the number of elements into the appropriate slot.
- llvm::Value *NumElementsPtr
- = CGF.Builder.CreateBitCast(CookiePtr,
- CGF.ConvertType(SizeTy)->getPointerTo(AS));
- CGF.Builder.CreateStore(NumElements, NumElementsPtr);
+ llvm::Type *NumElementsTy = CGF.ConvertType(SizeTy)->getPointerTo(AS);
+ llvm::Value *NumElementsPtr =
+ CGF.Builder.CreateBitCast(CookiePtr, NumElementsTy);
+ llvm::Instruction *SI = CGF.Builder.CreateStore(NumElements, NumElementsPtr);
+ if (CGM.getLangOpts().Sanitize.has(SanitizerKind::Address) && AS == 0 &&
+ expr->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
+ // The store to the CookiePtr does not need to be instrumented.
+ CGM.getSanitizerMetadata()->disableSanitizerForInstruction(SI);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, NumElementsTy, false);
+ llvm::Constant *F =
+ CGM.CreateRuntimeFunction(FTy, "__asan_poison_cxx_array_cookie");
+ CGF.Builder.CreateCall(F, NumElementsPtr);
+ }
// Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely.
@@ -1499,7 +1541,18 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
- return CGF.Builder.CreateLoad(numElementsPtr);
+ if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Address) || AS != 0)
+ return CGF.Builder.CreateLoad(numElementsPtr);
+ // In asan mode emit a function call instead of a regular load and let the
+ // run-time deal with it: if the shadow is properly poisoned return the
+ // cookie, otherwise return 0 to avoid an infinite loop calling DTORs.
+ // We can't simply ignore this load using nosanitize metadata because
+ // the metadata may be lost.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.SizeTy, CGF.SizeTy->getPointerTo(0), false);
+ llvm::Constant *F =
+ CGM.CreateRuntimeFunction(FTy, "__asan_load_cxx_array_cookie");
+ return CGF.Builder.CreateCall(F, numElementsPtr);
}
CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
@@ -1656,6 +1709,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// If the variable is thread-local, so is its guard variable.
guard->setThreadLocalMode(var->getThreadLocalMode());
+ // The ABI says: It is suggested that it be emitted in the same COMDAT group
+ // as the associated data object
+ llvm::Comdat *C = var->getComdat();
+ if (!D.isLocalVarDecl() && C) {
+ guard->setComdat(C);
+ CGF.CurFn->setComdat(C);
+ } else if (CGM.supportsCOMDAT() && guard->isWeakForLinker()) {
+ guard->setComdat(CGM.getModule().getOrInsertComdat(guard->getName()));
+ }
+
CGM.setStaticLocalDeclGuardAddress(&D, guard);
}
@@ -1851,7 +1914,7 @@ getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
llvm::Function *
ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
- llvm::GlobalVariable *Var) {
+ llvm::Value *Val) {
// Mangle the name for the thread_local wrapper function.
SmallString<256> WrapperName;
{
@@ -1860,10 +1923,10 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
Out.flush();
}
- if (llvm::Value *V = Var->getParent()->getNamedValue(WrapperName))
+ if (llvm::Value *V = CGM.getModule().getNamedValue(WrapperName))
return cast<llvm::Function>(V);
- llvm::Type *RetTy = Var->getType();
+ llvm::Type *RetTy = Val->getType();
if (VD->getType()->isReferenceType())
RetTy = RetTy->getPointerElementType();
@@ -1878,11 +1941,29 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
}
void ItaniumCXXABI::EmitThreadLocalInitFuncs(
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc) {
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
- const VarDecl *VD = Decls[I].first;
- llvm::GlobalVariable *Var = Decls[I].second;
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals, ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) {
+ llvm::Function *InitFunc = nullptr;
+ if (!CXXThreadLocalInits.empty()) {
+ // Generate a guarded initialization function.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init",
+ SourceLocation(),
+ /*TLS=*/true);
+ llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
+ CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
+ llvm::GlobalVariable::InternalLinkage,
+ llvm::ConstantInt::get(CGM.Int8Ty, 0), "__tls_guard");
+ Guard->setThreadLocal(true);
+ CodeGenFunction(CGM)
+ .GenerateCXXGlobalInitFunc(InitFunc, CXXThreadLocalInits, Guard);
+ }
+ for (unsigned I = 0, N = CXXThreadLocals.size(); I != N; ++I) {
+ const VarDecl *VD = CXXThreadLocals[I].first;
+ llvm::GlobalVariable *Var = CXXThreadLocals[I].second;
// Some targets require that all access to thread local variables go through
// the thread wrapper. This means that we cannot attempt to create a thread
@@ -1951,7 +2032,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
LI->setAlignment(CGM.getContext().getDeclAlign(VD).getQuantity());
Val = LI;
}
-
+ if (Val->getType() != Wrapper->getReturnType())
+ Val = Builder.CreatePointerBitCastOrAddrSpaceCast(
+ Val, Wrapper->getReturnType(), "");
Builder.CreateRet(Val);
}
}
@@ -1962,8 +2045,7 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
QualType T = VD->getType();
llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
- llvm::Function *Wrapper =
- getOrCreateThreadLocalWrapper(VD, cast<llvm::GlobalVariable>(Val));
+ llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val);
Val = CGF.Builder.CreateCall(Wrapper);
@@ -2125,6 +2207,11 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
/*Constant=*/true,
llvm::GlobalValue::ExternalLinkage, nullptr,
Name);
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (RD->hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
+ }
}
return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
@@ -2247,7 +2334,11 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
// FIXME: this may need to be reconsidered if the key function
// changes.
- return CGM.getVTables().isVTableExternal(RD);
+ if (CGM.getVTables().isVTableExternal(RD))
+ return true;
+
+ if (RD->hasAttr<DLLImportAttr>())
+ return true;
}
return false;
@@ -2742,7 +2833,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
if (Base->isVirtual()) {
// Mark the virtual base as seen.
- if (!Bases.VirtualBases.insert(BaseDecl)) {
+ if (!Bases.VirtualBases.insert(BaseDecl).second) {
// If this virtual base has been seen before, then the class is diamond
// shaped.
Flags |= ItaniumRTTIBuilder::VMI_DiamondShaped;
@@ -2752,7 +2843,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
}
} else {
// Mark the non-virtual base as seen.
- if (!Bases.NonVirtualBases.insert(BaseDecl)) {
+ if (!Bases.NonVirtualBases.insert(BaseDecl).second) {
// If this non-virtual base has been seen before, then the class has non-
// diamond shaped repeated inheritance.
Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
@@ -2988,3 +3079,128 @@ ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness(
assert(Linkage == llvm::GlobalValue::WeakODRLinkage);
return RUK_NonUniqueVisible;
}
+
+// 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 and base structors are not equivalent if there are any virtual
+ // bases, so emit separate functions.
+ 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);
+
+ if (llvm::GlobalValue::isDiscardableIfUnused(Linkage))
+ return StructorCodegen::RAUW;
+
+ // FIXME: Should we allow available_externally aliases?
+ if (!llvm::GlobalAlias::isValidLinkage(Linkage))
+ return StructorCodegen::RAUW;
+
+ if (llvm::GlobalValue::isWeakForLinker(Linkage)) {
+ // Only ELF supports COMDATs with arbitrary names (C5/D5).
+ if (CGM.getTarget().getTriple().isOSBinFormatELF())
+ return StructorCodegen::COMDAT;
+ return StructorCodegen::Emit;
+ }
+
+ return StructorCodegen::Alias;
+}
+
+static void emitConstructorDestructorAlias(CodeGenModule &CGM,
+ GlobalDecl AliasDecl,
+ GlobalDecl TargetDecl) {
+ llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl);
+
+ StringRef MangledName = CGM.getMangledName(AliasDecl);
+ llvm::GlobalValue *Entry = CGM.GetGlobalValue(MangledName);
+ if (Entry && !Entry->isDeclaration())
+ return;
+
+ auto *Aliasee = cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(TargetDecl));
+ llvm::PointerType *AliasType = Aliasee->getType();
+
+ // Create the alias with no name.
+ auto *Alias = llvm::GlobalAlias::create(
+ AliasType->getElementType(), 0, Linkage, "", Aliasee, &CGM.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.
+ CGM.setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
+}
+
+void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
+ StructorType Type) {
+ auto *CD = dyn_cast<CXXConstructorDecl>(MD);
+ const CXXDestructorDecl *DD = CD ? nullptr : cast<CXXDestructorDecl>(MD);
+
+ StructorCodegen CGType = getCodegenToUse(CGM, MD);
+
+ 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 (CGType == StructorCodegen::Alias || CGType == StructorCodegen::COMDAT) {
+ emitConstructorDestructorAlias(CGM, CompleteDecl, BaseDecl);
+ return;
+ }
+
+ if (CGType == StructorCodegen::RAUW) {
+ StringRef MangledName = CGM.getMangledName(CompleteDecl);
+ auto *Aliasee = cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(BaseDecl));
+ CGM.addReplacement(MangledName, Aliasee);
+ return;
+ }
+ }
+
+ // The base destructor is equivalent to the base destructor of its
+ // 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 (DD && Type == StructorType::Base && CGType != StructorCodegen::COMDAT &&
+ !CGM.TryEmitBaseDestructorAsAlias(DD))
+ return;
+
+ llvm::Function *Fn = CGM.codegenCXXStructor(MD, Type);
+
+ if (CGType == StructorCodegen::COMDAT) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ if (DD)
+ getMangleContext().mangleCXXDtorComdat(DD, Out);
+ else
+ getMangleContext().mangleCXXCtorComdat(CD, Out);
+ llvm::Comdat *C = CGM.getModule().getOrInsertComdat(Out.str());
+ Fn->setComdat(C);
+ }
+}
OpenPOWER on IntegriCloud