Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/include/clang/AST/VTableBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class VTableComponent {
case CK_CompleteDtorPointer:
return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete);
case CK_DeletingDtorPointer:
return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting);
return GlobalDecl(DtorDecl, CXXDtorType::Dtor_VectorDeleting);
case CK_VCallOffset:
case CK_VBaseOffset:
case CK_OffsetToTop:
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Basic/ABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ enum CXXCtorType {

/// C++ destructor types.
enum CXXDtorType {
Dtor_Deleting, ///< Deleting dtor
Dtor_Complete, ///< Complete object dtor
Dtor_Base, ///< Base object dtor
Dtor_Comdat ///< The COMDAT used for dtors
Dtor_Deleting, ///< Deleting dtor
Dtor_Complete, ///< Complete object dtor
Dtor_Base, ///< Base object dtor
Dtor_Comdat, ///< The COMDAT used for dtors
Dtor_VectorDeleting ///< Vector deleting dtor
};

} // end namespace clang
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5994,6 +5994,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
case Dtor_Comdat:
Out << "D5";
break;
case Dtor_VectorDeleting:
llvm_unreachable("Itanium ABI does not use vector deleting dtors");
}
}

Expand Down
10 changes: 6 additions & 4 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1484,8 +1484,7 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// <operator-name> ::= ?_G # scalar deleting destructor
case Dtor_Deleting: Out << "?_G"; return;
// <operator-name> ::= ?_E # vector deleting destructor
// FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need
// it.
case Dtor_VectorDeleting: Out << "?_E"; return;
case Dtor_Comdat:
llvm_unreachable("not expecting a COMDAT");
}
Expand Down Expand Up @@ -2917,9 +2916,12 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// ::= @ # structors (they have no declared return type)
if (IsStructor) {
if (isa<CXXDestructorDecl>(D) && isStructorDecl(D)) {
// The scalar deleting destructor takes an extra int argument which is not
// The deleting destructors take an extra argument of type int that indicates
// whether the storage for the object should be deleted and whether a single
// object or an array of objects is being destroyed. This extra argument is not
// reflected in the AST.
if (StructorType == Dtor_Deleting) {
if (StructorType == Dtor_Deleting ||
StructorType == Dtor_VectorDeleting) {
Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
return;
}
Expand Down
22 changes: 15 additions & 7 deletions clang/lib/AST/VTableBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,6 @@ void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");

// Add both the complete destructor and the deleting destructor.
Components.push_back(VTableComponent::MakeCompleteDtor(DD));
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
Expand Down Expand Up @@ -1733,7 +1732,7 @@ void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
const CXXMethodDecl *MD = I.first;
const MethodInfo &MI = I.second;
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
= MI.VTableIndex - AddressPoint;
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
= MI.VTableIndex + 1 - AddressPoint;
Expand Down Expand Up @@ -2655,7 +2654,11 @@ class VFTableBuilder {
MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.getVBaseWithVPtr(),
WhichVFPtr.NonVirtualOffset, MI.VFTableIndex);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
if (!Context.getTargetInfo().getCXXABI().isMicrosoft()) {
MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
} else {
MethodVFTableLocations[GlobalDecl(DD, Dtor_VectorDeleting)] = Loc;
}
} else {
MethodVFTableLocations[MD] = Loc;
}
Expand Down Expand Up @@ -3285,7 +3288,10 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
const CXXDestructorDecl *DD = Component.getDestructorDecl();

DD->printQualifiedName(Out);
Out << "() [scalar deleting]";
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
Out << "() [vector deleting]";
else
Out << "() [deleting]";

if (DD->isPureVirtual())
Out << " [pure]";
Expand Down Expand Up @@ -3756,7 +3762,7 @@ void MicrosoftVTableContext::dumpMethodLocations(
PredefinedIdentKind::PrettyFunctionNoVirtual, MD);

if (isa<CXXDestructorDecl>(MD)) {
IndicesMap[I.second] = MethodName + " [scalar deleting]";
IndicesMap[I.second] = MethodName + " [deleting]";
} else {
IndicesMap[I.second] = MethodName;
}
Expand Down Expand Up @@ -3872,8 +3878,10 @@ MethodVFTableLocation
MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) {
assert(hasVtableSlot(cast<CXXMethodDecl>(GD.getDecl())) &&
"Only use this method for virtual methods or dtors");
if (isa<CXXDestructorDecl>(GD.getDecl()))
assert(GD.getDtorType() == Dtor_Deleting);
if (isa<CXXDestructorDecl>(GD.getDecl())) {
assert(GD.getDtorType() == Dtor_Deleting ||
GD.getDtorType() == Dtor_VectorDeleting);
}

GD = GD.getCanonicalDecl();

Expand Down
42 changes: 41 additions & 1 deletion clang/lib/CodeGen/CGCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
// requires explicit comdat support in the IL.
if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
return true;

// Create the alias with no name.
auto *Alias = llvm::GlobalAlias::create(AliasValueType, 0, Linkage, "",
Aliasee, &getModule());
Expand All @@ -201,7 +200,48 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
return false;
}

/// Emit a definition as a global alias for another definition, unconditionally.
/// Use this function with care as it can produce invalid aliases. Generally
/// this function should be used only where there is an ABI requirement to emit
/// an alias.
void CodeGenModule::EmitDefinitionAsAlias(GlobalDecl AliasDecl, GlobalDecl TargetDecl) {

// Derive the type for the alias.
llvm::PointerType *AliasValueType =
getTypes().GetFunctionType(AliasDecl)->getPointerTo();
auto *Aliasee = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));

// Determine the linkage type for the alias.
llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);

// Create the alias with no name.
auto *Alias = llvm::GlobalAlias::create(AliasValueType, 0, Linkage, "",
Aliasee, &getModule());
// Destructors are always unnamed_addr.
Alias->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);

// Set any additional necessary attributes for the alias.
SetCommonAttributes(AliasDecl, Alias);
}

llvm::Function *CodeGenModule::codegenCXXStructor(GlobalDecl GD) {
// The Microsoft ABI requires that the vector deleting destructor
// be weak aliased to the scalar deleting destructor.
auto Dtor = dyn_cast<CXXDestructorDecl>(GD.getDecl());
if (Dtor && getTarget().getCXXABI().isMicrosoft() &&
GD.getDtorType() == Dtor_VectorDeleting) {
const CXXDestructorDecl *DtorDecl = cast<CXXDestructorDecl>(GD.getDecl());

// Create GlobalDecl objects with the correct type for the vector and scalar
// deleting destructors.
GlobalDecl VectorDtorGD(DtorDecl, Dtor_VectorDeleting);
GlobalDecl ScalarDtorGD(DtorDecl, Dtor_Deleting);

// Emit an alias from the vector deleting destructor to the scalar deleting
// destructor.
EmitDefinitionAsAlias(VectorDtorGD, ScalarDtorGD);

}
const CGFunctionInfo &FnInfo = getTypes().arrangeCXXStructorDeclaration(GD);
auto *Fn = cast<llvm::Function>(
getAddrOfCXXStructor(GD, &FnInfo, /*FnType=*/nullptr,
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/CodeGen/CGCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,21 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, Address ptr,
numElements = readArrayCookieImpl(CGF, allocAddr, cookieSize);
}

void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, Address ptr,
QualType eltTy, llvm::Value *&numElements,
llvm::Value *&allocPtr, CharUnits &cookieSize) {
// FIXME
// Assert that we have a cookie.

// Derive a char* in the same address space as the pointer.
ptr = ptr.withElementType(CGF.Int8Ty);

cookieSize = getArrayCookieSizeImpl(eltTy);
Address allocAddr = CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize);
allocPtr = allocAddr.emitRawPointer(CGF);
numElements = readArrayCookieImpl(CGF, allocAddr, cookieSize);
}

llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
Address ptr,
CharUnits cookieSize) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,12 @@ class CGCXXABI {
QualType ElementType, llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize);

/// Reads the array cookie associated with the given pointer,
/// that should have one.
virtual void ReadArrayCookie(CodeGenFunction &CGF, Address Ptr,
QualType ElementType, llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize);

/// Return whether the given global decl needs a VTT parameter.
virtual bool NeedsVTTParameter(GlobalDecl GD);

Expand Down
112 changes: 102 additions & 10 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,88 @@ static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF,
return true;
}

namespace {
llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF,
const CXXDestructorDecl *DD) {
if (Expr *ThisArg = DD->getOperatorDeleteThisArg())
return CGF.EmitScalarExpr(ThisArg);
return CGF.LoadCXXThis();
}
}

void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
CodeGenFunction &CGF,
llvm::Value *ShouldDeleteCondition,
bool ReturnAfterDelete) {
Address ThisPtr = CGF.LoadCXXThisAddress();
// llvm::Value *ThisPtr = LoadThisForDtorDelete(CGF, DD);
// llvm::BasicBlock *End = CGF.createBasicBlock("dtor.end");
llvm::BasicBlock *ScalarBB = CGF.createBasicBlock("dtor.scalar");
llvm::BasicBlock *callDeleteBB =
CGF.createBasicBlock("dtor.call_delete_after_array_destroy");
llvm::BasicBlock *VectorBB = CGF.createBasicBlock("dtor.vector");
auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType());
llvm::Value *CheckTheBitForArrayDestroy = CGF.Builder.CreateAnd(
ShouldDeleteCondition,
llvm::Constant::getIntegerValue(CondTy, llvm::APInt(CondTy->getBitWidth(),
/*val=*/2)));
llvm::Value *ShouldDestroyArray =
CGF.Builder.CreateIsNull(CheckTheBitForArrayDestroy);
CGF.Builder.CreateCondBr(ShouldDestroyArray, ScalarBB, VectorBB);

CGF.EmitBlock(VectorBB);

llvm::Value *numElements = nullptr;
llvm::Value *allocatedPtr = nullptr;
CharUnits cookieSize;
QualType EltTy = DD->getThisType()->getPointeeType();
CGF.CGM.getCXXABI().ReadArrayCookie(CGF, ThisPtr, EltTy, numElements,
allocatedPtr, cookieSize);

// Destroy the elements.
QualType::DestructionKind dtorKind = EltTy.isDestructedType();

assert(dtorKind);
assert(numElements && "no element count for a type with a destructor!");

CharUnits elementSize = CGF.getContext().getTypeSizeInChars(EltTy);
CharUnits elementAlign =
ThisPtr.getAlignment().alignmentOfArrayElement(elementSize);

llvm::Value *arrayBegin = ThisPtr.emitRawPointer(CGF);
llvm::Value *arrayEnd = CGF.Builder.CreateInBoundsGEP(
ThisPtr.getElementType(), arrayBegin, numElements, "delete.end");

// Note that it is legal to allocate a zero-length array, and we
// can never fold the check away because the length should always
// come from a cookie.
CGF.emitArrayDestroy(arrayBegin, arrayEnd, EltTy, elementAlign,
CGF.getDestroyer(dtorKind),
/*checkZeroLength*/ true, CGF.needsEHCleanup(dtorKind));

llvm::BasicBlock *VectorBBCont = CGF.createBasicBlock("dtor.vector.cont");
CGF.EmitBlock(VectorBBCont);

llvm::Value *CheckTheBitForDeleteCall = CGF.Builder.CreateAnd(
ShouldDeleteCondition,
llvm::Constant::getIntegerValue(CondTy, llvm::APInt(CondTy->getBitWidth(),
/*val=*/1)));

llvm::Value *ShouldCallDelete =
CGF.Builder.CreateIsNull(CheckTheBitForDeleteCall);
CGF.Builder.CreateCondBr(ShouldCallDelete, CGF.ReturnBlock.getBlock(),
callDeleteBB);
CGF.EmitBlock(callDeleteBB);
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
const CXXRecordDecl *ClassDecl = Dtor->getParent();
CGF.EmitDeleteCall(Dtor->getOperatorDelete(), allocatedPtr,
CGF.getContext().getTagDeclType(ClassDecl));

// FIXME figure how to go to the end properly
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
CGF.EmitBlock(ScalarBB);
}

/// EmitDestructorBody - Emits the body of the current destructor.
void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
Expand Down Expand Up @@ -1462,7 +1544,11 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// outside of the function-try-block, which means it's always
// possible to delegate the destructor body to the complete
// destructor. Do so.
if (DtorType == Dtor_Deleting) {
if (DtorType == Dtor_Deleting || DtorType == Dtor_VectorDeleting) {
if (CXXStructorImplicitParamValue && DtorType == Dtor_VectorDeleting) {
EmitConditionalArrayDtorCall(Dtor, *this, CXXStructorImplicitParamValue,
false);
}
RunCleanupsScope DtorEpilogue(*this);
EnterDtorCleanups(Dtor, Dtor_Deleting);
if (HaveInsertPoint()) {
Expand Down Expand Up @@ -1491,6 +1577,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
switch (DtorType) {
case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
case Dtor_VectorDeleting: llvm_unreachable("already handled vector deleting case");

case Dtor_Complete:
assert((Body || getTarget().getCXXABI().isMicrosoft()) &&
Expand Down Expand Up @@ -1567,12 +1654,12 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args)
}

namespace {
llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF,
const CXXDestructorDecl *DD) {
if (Expr *ThisArg = DD->getOperatorDeleteThisArg())
return CGF.EmitScalarExpr(ThisArg);
return CGF.LoadCXXThis();
}
// llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF,
// const CXXDestructorDecl *DD) {
// if (Expr *ThisArg = DD->getOperatorDeleteThisArg())
// return CGF.EmitScalarExpr(ThisArg);
// return CGF.LoadCXXThis();
// }

/// Call the operator delete associated with the current destructor.
struct CallDtorDelete final : EHScopeStack::Cleanup {
Expand All @@ -1592,8 +1679,12 @@ namespace {
bool ReturnAfterDelete) {
llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
llvm::Value *ShouldCallDelete
= CGF.Builder.CreateIsNull(ShouldDeleteCondition);
auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType());
llvm::Value *CheckTheBit = CGF.Builder.CreateAnd(
ShouldDeleteCondition, llvm::Constant::getIntegerValue(
CondTy, llvm::APInt(CondTy->getBitWidth(),
/*val=*/1)));
llvm::Value *ShouldCallDelete = CGF.Builder.CreateIsNull(CheckTheBit);
CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);

CGF.EmitBlock(callDeleteBB);
Expand Down Expand Up @@ -1857,9 +1948,10 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
if (DD->getOperatorDelete()->isDestroyingOperatorDelete())
EmitConditionalDtorDeleteCall(*this, CXXStructorImplicitParamValue,
/*ReturnAfterDelete*/true);
else
else {
EHStack.pushCleanup<CallDtorDeleteConditional>(
NormalAndEHCleanup, CXXStructorImplicitParamValue);
}
} else {
if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) {
const CXXRecordDecl *ClassDecl = DD->getParent();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,7 @@ class CodeGenModule : public CodeGenTypeCache {
void EmitGlobal(GlobalDecl D);

bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
void EmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);

llvm::GlobalValue *GetGlobalValue(StringRef Ref);

Expand Down
Loading
Loading