summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGExprCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-10-13 01:55:36 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-10-13 01:55:36 +0000
commit5b34958b46dc14267d1b06099c3bd43e748716fc (patch)
treec3e9bded9164d23dfcc44b90914d040d087e18e5 /clang/lib/CodeGen/CGExprCXX.cpp
parentad38fbffad842c3baf4589139271d16d14af0357 (diff)
downloadbcm5719-llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.tar.gz
bcm5719-llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.zip
Support for destroying operator delete, per C++2a proposal P0722.
This feature is not (yet) approved by the C++ committee, so this is liable to be reverted or significantly modified based on committee feedback. No functionality change intended for existing code (a new type must be defined in namespace std to take advantage of this feature). llvm-svn: 315662
Diffstat (limited to 'clang/lib/CodeGen/CGExprCXX.cpp')
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp95
1 files changed, 72 insertions, 23 deletions
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 8ee236ddd86..3eb4bd6b901 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1311,29 +1311,44 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
llvm_unreachable("predeclared global operator new/delete is missing");
}
-static std::pair<bool, bool>
-shouldPassSizeAndAlignToUsualDelete(const FunctionProtoType *FPT) {
+namespace {
+/// The parameters to pass to a usual operator delete.
+struct UsualDeleteParams {
+ bool DestroyingDelete = false;
+ bool Size = false;
+ bool Alignment = false;
+};
+}
+
+static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *FD) {
+ UsualDeleteParams Params;
+
+ const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();
// The first argument is always a void*.
++AI;
- // Figure out what other parameters we should be implicitly passing.
- bool PassSize = false;
- bool PassAlignment = false;
+ // The next parameter may be a std::destroying_delete_t.
+ if (FD->isDestroyingOperatorDelete()) {
+ Params.DestroyingDelete = true;
+ assert(AI != AE);
+ ++AI;
+ }
+ // Figure out what other parameters we should be implicitly passing.
if (AI != AE && (*AI)->isIntegerType()) {
- PassSize = true;
+ Params.Size = true;
++AI;
}
if (AI != AE && (*AI)->isAlignValT()) {
- PassAlignment = true;
+ Params.Alignment = true;
++AI;
}
assert(AI == AE && "unexpected usual deallocation function parameter");
- return {PassSize, PassAlignment};
+ return Params;
}
namespace {
@@ -1386,25 +1401,27 @@ namespace {
OperatorDelete->getType()->getAs<FunctionProtoType>();
CallArgList DeleteArgs;
- // The first argument is always a void*.
+ // The first argument is always a void* (or C* for a destroying operator
+ // delete for class type C).
DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(0));
// Figure out what other parameters we should be implicitly passing.
- bool PassSize = false;
- bool PassAlignment = false;
+ UsualDeleteParams Params;
if (NumPlacementArgs) {
// A placement deallocation function is implicitly passed an alignment
// if the placement allocation function was, but is never passed a size.
- PassAlignment = PassAlignmentToPlacementDelete;
+ Params.Alignment = PassAlignmentToPlacementDelete;
} else {
// For a non-placement new-expression, 'operator delete' can take a
// size and/or an alignment if it has the right parameters.
- std::tie(PassSize, PassAlignment) =
- shouldPassSizeAndAlignToUsualDelete(FPT);
+ Params = getUsualDeleteParams(OperatorDelete);
}
+ assert(!Params.DestroyingDelete &&
+ "should not call destroying delete in a new-expression");
+
// The second argument can be a std::size_t (for non-placement delete).
- if (PassSize)
+ if (Params.Size)
DeleteArgs.add(Traits::get(CGF, AllocSize),
CGF.getContext().getSizeType());
@@ -1412,7 +1429,7 @@ namespace {
// is an enum whose underlying type is std::size_t.
// FIXME: Use the right type as the parameter type. Note that in a call
// to operator delete(size_t, ...), we may not have it available.
- if (PassAlignment)
+ if (Params.Alignment)
DeleteArgs.add(RValue::get(llvm::ConstantInt::get(
CGF.SizeTy, AllocAlign.getQuantity())),
CGF.getContext().getSizeType());
@@ -1715,9 +1732,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
CallArgList DeleteArgs;
- std::pair<bool, bool> PassSizeAndAlign =
- shouldPassSizeAndAlignToUsualDelete(DeleteFTy);
-
+ auto Params = getUsualDeleteParams(DeleteFD);
auto ParamTypeIt = DeleteFTy->param_type_begin();
// Pass the pointer itself.
@@ -1725,8 +1740,16 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
+ // Pass the std::destroying_delete tag if present.
+ if (Params.DestroyingDelete) {
+ QualType DDTag = *ParamTypeIt++;
+ // Just pass an 'undef'. We expect the tag type to be an empty struct.
+ auto *V = llvm::UndefValue::get(getTypes().ConvertType(DDTag));
+ DeleteArgs.add(RValue::get(V), DDTag);
+ }
+
// Pass the size if the delete function has a size_t parameter.
- if (PassSizeAndAlign.first) {
+ if (Params.Size) {
QualType SizeType = *ParamTypeIt++;
CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
llvm::Value *Size = llvm::ConstantInt::get(ConvertType(SizeType),
@@ -1745,7 +1768,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
}
// Pass the alignment if the delete function has an align_val_t parameter.
- if (PassSizeAndAlign.second) {
+ if (Params.Alignment) {
QualType AlignValType = *ParamTypeIt++;
CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits(
getContext().getTypeAlignIfKnown(DeleteTy));
@@ -1787,6 +1810,21 @@ CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
OperatorDelete, ElementType);
}
+/// Emit the code for deleting a single object with a destroying operator
+/// delete. If the element type has a non-virtual destructor, Ptr has already
+/// been converted to the type of the parameter of 'operator delete'. Otherwise
+/// Ptr points to an object of the static type.
+static void EmitDestroyingObjectDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE, Address Ptr,
+ QualType ElementType) {
+ auto *Dtor = ElementType->getAsCXXRecordDecl()->getDestructor();
+ if (Dtor && Dtor->isVirtual())
+ CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
+ Dtor);
+ else
+ CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType);
+}
+
/// Emit the code for deleting a single object.
static void EmitObjectDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *DE,
@@ -1801,6 +1839,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
DE->getExprLoc(), Ptr.getPointer(),
ElementType);
+ const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
+ assert(!OperatorDelete->isDestroyingOperatorDelete());
+
// Find the destructor for the type, if applicable. If the
// destructor is virtual, we'll just emit the vcall and return.
const CXXDestructorDecl *Dtor = nullptr;
@@ -1820,7 +1861,6 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
// Make sure that we call delete even if the dtor throws.
// This doesn't have to a conditional cleanup because we're going
// to pop it off in a second.
- const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
Ptr.getPointer(),
OperatorDelete, ElementType);
@@ -1932,10 +1972,19 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
EmitBlock(DeleteNotNull);
+ QualType DeleteTy = E->getDestroyedType();
+
+ // A destroying operator delete overrides the entire operation of the
+ // delete expression.
+ if (E->getOperatorDelete()->isDestroyingOperatorDelete()) {
+ EmitDestroyingObjectDelete(*this, E, Ptr, DeleteTy);
+ EmitBlock(DeleteEnd);
+ return;
+ }
+
// We might be deleting a pointer to array. If so, GEP down to the
// first non-array element.
// (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*)
- QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType();
if (DeleteTy->isConstantArrayType()) {
llvm::Value *Zero = Builder.getInt32(0);
SmallVector<llvm::Value*,8> GEP;
OpenPOWER on IntegriCloud