[cfe-commits] r124373 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/CodeGen/CGCXXABI.cpp lib/CodeGen/CGCXXABI.h lib/CodeGen/CGExprCXX.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Sema/SemaExprCXX.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/delete-two-arg.cpp
John McCall
rjmccall at apple.com
Thu Jan 27 01:37:57 PST 2011
Author: rjmccall
Date: Thu Jan 27 03:37:56 2011
New Revision: 124373
URL: http://llvm.org/viewvc/llvm-project?rev=124373&view=rev
Log:
Do a proper recursive lookup when deciding whether a class's usual
deallocation function has a two-argument form. Store the result of this
check in new[] and delete[] nodes.
Fixes rdar://problem/8913519
Modified:
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/CodeGen/CGCXXABI.cpp
cfe/trunk/lib/CodeGen/CGCXXABI.h
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Jan 27 03:37:56 2011
@@ -992,8 +992,11 @@
bool Initializer : 1;
// Do we allocate an array? If so, the first SubExpr is the size expression.
bool Array : 1;
+ // If this is an array allocation, does the usual deallocation
+ // function for the allocated type want to know the allocated size?
+ bool UsualArrayDeleteWantsSize : 1;
// The number of placement new arguments.
- unsigned NumPlacementArgs : 15;
+ unsigned NumPlacementArgs : 14;
// The number of constructor arguments. This may be 1 even for non-class
// types; use the pseudo copy constructor.
unsigned NumConstructorArgs : 14;
@@ -1029,8 +1032,8 @@
SourceRange TypeIdParens,
Expr *arraySize, CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
- FunctionDecl *operatorDelete, QualType ty,
- TypeSourceInfo *AllocatedTypeInfo,
+ FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
+ QualType ty, TypeSourceInfo *AllocatedTypeInfo,
SourceLocation startLoc, SourceLocation endLoc,
SourceLocation constructorLParen,
SourceLocation constructorRParen);
@@ -1082,9 +1085,14 @@
SourceRange getTypeIdParens() const { return TypeIdParens; }
bool isGlobalNew() const { return GlobalNew; }
- void setGlobalNew(bool V) { GlobalNew = V; }
bool hasInitializer() const { return Initializer; }
- void setHasInitializer(bool V) { Initializer = V; }
+
+ /// Answers whether the usual array deallocation function for the
+ /// allocated type expects the size of the allocation as a
+ /// parameter.
+ bool doesUsualArrayDeleteWantSize() const {
+ return UsualArrayDeleteWantsSize;
+ }
unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
@@ -1169,6 +1177,9 @@
// to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm
// will be true).
bool ArrayFormAsWritten : 1;
+ // Does the usual deallocation function for the element type require
+ // a size_t argument?
+ bool UsualArrayDeleteWantsSize : 1;
// Points to the operator delete overload that is used. Could be a member.
FunctionDecl *OperatorDelete;
// The pointer expression to be deleted.
@@ -1177,12 +1188,13 @@
SourceLocation Loc;
public:
CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
- bool arrayFormAsWritten, FunctionDecl *operatorDelete,
- Expr *arg, SourceLocation loc)
+ bool arrayFormAsWritten, bool usualArrayDeleteWantsSize,
+ FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc)
: Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false,
arg->containsUnexpandedParameterPack()),
GlobalDelete(globalDelete),
ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten),
+ UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
OperatorDelete(operatorDelete), Argument(arg), Loc(loc) { }
explicit CXXDeleteExpr(EmptyShell Shell)
: Expr(CXXDeleteExprClass, Shell), OperatorDelete(0), Argument(0) { }
@@ -1191,6 +1203,14 @@
bool isArrayForm() const { return ArrayForm; }
bool isArrayFormAsWritten() const { return ArrayFormAsWritten; }
+ /// Answers whether the usual array deallocation function for the
+ /// allocated type expects the size of the allocation as a
+ /// parameter. This can be true even if the actual deallocation
+ /// function that we're using doesn't want a size.
+ bool doesUsualArrayDeleteWantSize() const {
+ return UsualArrayDeleteWantsSize;
+ }
+
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
Expr *getArgument() { return cast<Expr>(Argument); }
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Thu Jan 27 03:37:56 2011
@@ -111,7 +111,8 @@
SourceRange TypeIdParens, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
- FunctionDecl *operatorDelete, QualType ty,
+ FunctionDecl *operatorDelete,
+ bool usualArrayDeleteWantsSize, QualType ty,
TypeSourceInfo *AllocatedTypeInfo,
SourceLocation startLoc, SourceLocation endLoc,
SourceLocation constructorLParen,
@@ -119,8 +120,9 @@
: Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary,
ty->isDependentType(), ty->isDependentType(),
ty->containsUnexpandedParameterPack()),
- GlobalNew(globalNew),
- Initializer(initializer), SubExprs(0), OperatorNew(operatorNew),
+ GlobalNew(globalNew), Initializer(initializer),
+ UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
+ SubExprs(0), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor),
AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens),
StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen),
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Thu Jan 27 03:37:56 2011
@@ -142,13 +142,14 @@
CGF.EmitReturnOfRValue(RV, ResultType);
}
-CharUnits CGCXXABI::GetArrayCookieSize(QualType ElementType) {
+CharUnits CGCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
return CharUnits::Zero();
}
llvm::Value *CGCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
+ const CXXNewExpr *expr,
QualType ElementType) {
// Should never be called.
ErrorUnsupportedABI(CGF, "array cookie initialization");
@@ -156,7 +157,8 @@
}
void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
- QualType ElementType, llvm::Value *&NumElements,
+ const CXXDeleteExpr *expr, QualType ElementType,
+ llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize) {
ErrorUnsupportedABI(CGF, "array cookie reading");
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Thu Jan 27 03:37:56 2011
@@ -189,7 +189,7 @@
///
/// \param ElementType - the allocated type of the expression,
/// i.e. the pointee type of the expression result type
- virtual CharUnits GetArrayCookieSize(QualType ElementType);
+ virtual CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
/// Initialize the array cookie for the given allocation.
///
@@ -202,6 +202,7 @@
virtual llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
+ const CXXNewExpr *expr,
QualType ElementType);
/// Reads the array cookie associated with the given pointer,
@@ -218,6 +219,7 @@
/// \param CookieSize - an out parameter which will be initialized
/// with the size of the cookie, or zero if there is no cookie
virtual void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+ const CXXDeleteExpr *expr,
QualType ElementType, llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize);
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Thu Jan 27 03:37:56 2011
@@ -395,7 +395,7 @@
if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew))
return CharUnits::Zero();
- return CGF.CGM.getCXXABI().GetArrayCookieSize(E->getAllocatedType());
+ return CGF.CGM.getCXXABI().GetArrayCookieSize(E);
}
static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
@@ -1065,7 +1065,7 @@
if (AllocSize != AllocSizeWithoutCookie) {
assert(E->isArray());
NewPtr = CGM.getCXXABI().InitializeArrayCookie(CGF, NewPtr, NumElements,
- AllocType);
+ E, AllocType);
}
// If there's an operator delete, enter a cleanup to call it if an
@@ -1271,18 +1271,19 @@
/// Emit the code for deleting an array of objects.
static void EmitArrayDelete(CodeGenFunction &CGF,
- const FunctionDecl *OperatorDelete,
+ const CXXDeleteExpr *E,
llvm::Value *Ptr,
QualType ElementType) {
llvm::Value *NumElements = 0;
llvm::Value *AllocatedPtr = 0;
CharUnits CookieSize;
- CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, ElementType,
+ CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, E, ElementType,
NumElements, AllocatedPtr, CookieSize);
assert(AllocatedPtr && "ReadArrayCookie didn't set AllocatedPtr");
// Make sure that we call delete even if one of the dtors throws.
+ const FunctionDecl *OperatorDelete = E->getOperatorDelete();
CGF.EHStack.pushCleanup<CallArrayDelete>(NormalAndEHCleanup,
AllocatedPtr, OperatorDelete,
NumElements, ElementType,
@@ -1352,7 +1353,7 @@
cast<llvm::PointerType>(Ptr->getType())->getElementType());
if (E->isArrayForm()) {
- EmitArrayDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy);
+ EmitArrayDelete(*this, E, Ptr, DeleteTy);
} else {
EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy);
}
Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Jan 27 03:37:56 2011
@@ -47,7 +47,9 @@
return PtrDiffTy;
}
- bool NeedsArrayCookie(QualType ElementType);
+ bool NeedsArrayCookie(const CXXNewExpr *expr);
+ bool NeedsArrayCookie(const CXXDeleteExpr *expr,
+ QualType elementType);
public:
ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
@@ -105,12 +107,14 @@
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- CharUnits GetArrayCookieSize(QualType ElementType);
+ CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
+ const CXXNewExpr *expr,
QualType ElementType);
void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+ const CXXDeleteExpr *expr,
QualType ElementType, llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize);
@@ -140,12 +144,14 @@
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
- CharUnits GetArrayCookieSize(QualType ElementType);
+ CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
+ const CXXNewExpr *expr,
QualType ElementType);
void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+ const CXXDeleteExpr *expr,
QualType ElementType, llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize);
@@ -794,67 +800,49 @@
/************************** Array allocation cookies **************************/
-bool ItaniumCXXABI::NeedsArrayCookie(QualType ElementType) {
- ElementType = getContext().getBaseElementType(ElementType);
- const RecordType *RT = ElementType->getAs<RecordType>();
- if (!RT) return false;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
- // If the class has a non-trivial destructor, it always needs a cookie.
- if (!RD->hasTrivialDestructor()) return true;
-
+bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) {
// If the class's usual deallocation function takes two arguments,
- // it needs a cookie. Otherwise we don't need a cookie.
- const CXXMethodDecl *UsualDeallocationFunction = 0;
+ // it needs a cookie.
+ if (expr->doesUsualArrayDeleteWantSize())
+ return true;
+
+ // Otherwise, if the class has a non-trivial destructor, it always
+ // needs a cookie.
+ const CXXRecordDecl *record =
+ expr->getAllocatedType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ return (record && !record->hasTrivialDestructor());
+}
- // Usual deallocation functions of this form are always found on the
- // class.
- //
- // FIXME: what exactly is this code supposed to do if there's an
- // ambiguity? That's possible with using declarations.
- DeclarationName OpName =
- getContext().DeclarationNames.getCXXOperatorName(OO_Array_Delete);
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); Op != OpEnd; ++Op) {
- const CXXMethodDecl *Delete =
- cast<CXXMethodDecl>((*Op)->getUnderlyingDecl());
-
- if (Delete->isUsualDeallocationFunction()) {
- UsualDeallocationFunction = Delete;
- break;
- }
- }
-
- // No usual deallocation function, we don't need a cookie.
- if (!UsualDeallocationFunction)
- return false;
-
- // The usual deallocation function doesn't take a size_t argument,
- // so we don't need a cookie.
- if (UsualDeallocationFunction->getNumParams() == 1)
- return false;
-
- assert(UsualDeallocationFunction->getNumParams() == 2 &&
- "Unexpected deallocation function type!");
- return true;
+bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr,
+ QualType elementType) {
+ // If the class's usual deallocation function takes two arguments,
+ // it needs a cookie.
+ if (expr->doesUsualArrayDeleteWantSize())
+ return true;
+
+ // Otherwise, if the class has a non-trivial destructor, it always
+ // needs a cookie.
+ const CXXRecordDecl *record =
+ elementType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ return (record && !record->hasTrivialDestructor());
}
-CharUnits ItaniumCXXABI::GetArrayCookieSize(QualType ElementType) {
- if (!NeedsArrayCookie(ElementType))
+CharUnits ItaniumCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
+ if (!NeedsArrayCookie(expr))
return CharUnits::Zero();
- // Padding is the maximum of sizeof(size_t) and alignof(ElementType)
+ // Padding is the maximum of sizeof(size_t) and alignof(elementType)
ASTContext &Ctx = getContext();
return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
- Ctx.getTypeAlignInChars(ElementType));
+ Ctx.getTypeAlignInChars(expr->getAllocatedType()));
}
llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
+ const CXXNewExpr *expr,
QualType ElementType) {
- assert(NeedsArrayCookie(ElementType));
+ assert(NeedsArrayCookie(expr));
unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
@@ -887,6 +875,7 @@
void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
llvm::Value *Ptr,
+ const CXXDeleteExpr *expr,
QualType ElementType,
llvm::Value *&NumElements,
llvm::Value *&AllocPtr,
@@ -896,7 +885,7 @@
const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
// If we don't need an array cookie, bail out early.
- if (!NeedsArrayCookie(ElementType)) {
+ if (!NeedsArrayCookie(expr, ElementType)) {
AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
NumElements = 0;
CookieSize = CharUnits::Zero();
@@ -927,8 +916,8 @@
NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
}
-CharUnits ARMCXXABI::GetArrayCookieSize(QualType ElementType) {
- if (!NeedsArrayCookie(ElementType))
+CharUnits ARMCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
+ if (!NeedsArrayCookie(expr))
return CharUnits::Zero();
// On ARM, the cookie is always:
@@ -944,8 +933,9 @@
llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
+ const CXXNewExpr *expr,
QualType ElementType) {
- assert(NeedsArrayCookie(ElementType));
+ assert(NeedsArrayCookie(expr));
// NewPtr is a char*.
@@ -978,6 +968,7 @@
void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
llvm::Value *Ptr,
+ const CXXDeleteExpr *expr,
QualType ElementType,
llvm::Value *&NumElements,
llvm::Value *&AllocPtr,
@@ -987,7 +978,7 @@
const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
// If we don't need an array cookie, bail out early.
- if (!NeedsArrayCookie(ElementType)) {
+ if (!NeedsArrayCookie(expr, ElementType)) {
AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
NumElements = 0;
CookieSize = CharUnits::Zero();
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 27 03:37:56 2011
@@ -664,6 +664,61 @@
return move(Result);
}
+/// doesUsualArrayDeleteWantSize - Answers whether the usual
+/// operator delete[] for the given type has a size_t parameter.
+static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
+ QualType allocType) {
+ const RecordType *record =
+ allocType->getBaseElementTypeUnsafe()->getAs<RecordType>();
+ if (!record) return false;
+
+ // Try to find an operator delete[] in class scope.
+
+ DeclarationName deleteName =
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete);
+ LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName);
+ S.LookupQualifiedName(ops, record->getDecl());
+
+ // We're just doing this for information.
+ ops.suppressDiagnostics();
+
+ // Very likely: there's no operator delete[].
+ if (ops.empty()) return false;
+
+ // If it's ambiguous, it should be illegal to call operator delete[]
+ // on this thing, so it doesn't matter if we allocate extra space or not.
+ if (ops.isAmbiguous()) return false;
+
+ LookupResult::Filter filter = ops.makeFilter();
+ while (filter.hasNext()) {
+ NamedDecl *del = filter.next()->getUnderlyingDecl();
+
+ // C++0x [basic.stc.dynamic.deallocation]p2:
+ // A template instance is never a usual deallocation function,
+ // regardless of its signature.
+ if (isa<FunctionTemplateDecl>(del)) {
+ filter.erase();
+ continue;
+ }
+
+ // C++0x [basic.stc.dynamic.deallocation]p2:
+ // If class T does not declare [an operator delete[] with one
+ // parameter] but does declare a member deallocation function
+ // named operator delete[] with exactly two parameters, the
+ // second of which has type std::size_t, then this function
+ // is a usual deallocation function.
+ if (!cast<CXXMethodDecl>(del)->isUsualDeallocationFunction()) {
+ filter.erase();
+ continue;
+ }
+ }
+ filter.done();
+
+ if (!ops.isSingleResult()) return false;
+
+ const FunctionDecl *del = cast<FunctionDecl>(ops.getFoundDecl());
+ return (del->getNumParams() == 2);
+}
/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.:
/// @code new (memory) int[size][4] @endcode
@@ -839,6 +894,14 @@
UseGlobal, AllocType, ArraySize, PlaceArgs,
NumPlaceArgs, OperatorNew, OperatorDelete))
return ExprError();
+
+ // If this is an array allocation, compute whether the usual array
+ // deallocation function for the type has a size_t parameter.
+ bool UsualArrayDeleteWantsSize = false;
+ if (ArraySize && !AllocType->isDependentType())
+ UsualArrayDeleteWantsSize
+ = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType);
+
llvm::SmallVector<Expr *, 8> AllPlaceArgs;
if (OperatorNew) {
// Add default arguments, if any.
@@ -938,6 +1001,7 @@
PlaceArgs, NumPlaceArgs, TypeIdParens,
ArraySize, Constructor, Init,
ConsArgs, NumConsArgs, OperatorDelete,
+ UsualArrayDeleteWantsSize,
ResultType, AllocTypeInfo,
StartLoc,
Init ? ConstructorRParen :
@@ -1492,6 +1556,7 @@
FunctionDecl *OperatorDelete = 0;
bool ArrayFormAsWritten = ArrayForm;
+ bool UsualArrayDeleteWantsSize = false;
if (!Ex->isTypeDependent()) {
QualType Type = Ex->getType();
@@ -1587,6 +1652,21 @@
FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete))
return ExprError();
+ // If we're allocating an array of records, check whether the
+ // usual operator delete[] has a size_t parameter.
+ if (ArrayForm) {
+ // If the user specifically asked to use the global allocator,
+ // we'll need to do the lookup into the class.
+ if (UseGlobal)
+ UsualArrayDeleteWantsSize =
+ doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem);
+
+ // Otherwise, the usual operator delete[] should be the
+ // function we just found.
+ else if (isa<CXXMethodDecl>(OperatorDelete))
+ UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
+ }
+
if (!RD->hasTrivialDestructor())
if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) {
MarkDeclarationReferenced(StartLoc,
@@ -1606,13 +1686,14 @@
}
MarkDeclarationReferenced(StartLoc, OperatorDelete);
-
+
// FIXME: Check access and ambiguity of operator delete and destructor.
}
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
- ArrayFormAsWritten, OperatorDelete,
- Ex, StartLoc));
+ ArrayFormAsWritten,
+ UsualArrayDeleteWantsSize,
+ OperatorDelete, Ex, StartLoc));
}
/// \brief Check the use of the given variable as a C++ condition in an if,
Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Thu Jan 27 03:37:56 2011
@@ -1106,8 +1106,9 @@
void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
- E->setGlobalNew(Record[Idx++]);
- E->setHasInitializer(Record[Idx++]);
+ E->GlobalNew = Record[Idx++];
+ E->Initializer = Record[Idx++];
+ E->UsualArrayDeleteWantsSize = Record[Idx++];
bool isArray = Record[Idx++];
unsigned NumPlacementArgs = Record[Idx++];
unsigned NumCtorArgs = Record[Idx++];
@@ -1140,6 +1141,7 @@
E->GlobalDelete = Record[Idx++];
E->ArrayForm = Record[Idx++];
E->ArrayFormAsWritten = Record[Idx++];
+ E->UsualArrayDeleteWantsSize = Record[Idx++];
E->OperatorDelete = cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]));
E->Argument = Reader.ReadSubExpr();
E->Loc = ReadSourceLocation(Record, Idx);
Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Thu Jan 27 03:37:56 2011
@@ -1101,6 +1101,7 @@
VisitExpr(E);
Record.push_back(E->isGlobalNew());
Record.push_back(E->hasInitializer());
+ Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->isArray());
Record.push_back(E->getNumPlacementArgs());
Record.push_back(E->getNumConstructorArgs());
@@ -1125,6 +1126,7 @@
Record.push_back(E->isGlobalDelete());
Record.push_back(E->isArrayForm());
Record.push_back(E->isArrayFormAsWritten());
+ Record.push_back(E->doesUsualArrayDeleteWantSize());
Writer.AddDeclRef(E->getOperatorDelete(), Record);
Writer.AddStmt(E->getArgument());
Writer.AddSourceLocation(E->getSourceRange().getBegin(), Record);
Modified: cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp?rev=124373&r1=124372&r2=124373&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/delete-two-arg.cpp Thu Jan 27 03:37:56 2011
@@ -1,6 +1,70 @@
// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s
-struct A { void operator delete(void*,__typeof(sizeof(int))); int x; };
-void a(A* x) { delete x; }
+typedef __typeof(sizeof(int)) size_t;
-// CHECK: call void @_ZN1AdlEPvj(i8* %{{.*}}, i32 4)
+namespace test1 {
+ struct A { void operator delete(void*,size_t); int x; };
+
+ // CHECK: define void @_ZN5test11aEPNS_1AE(
+ void a(A *x) {
+ // CHECK: load
+ // CHECK-NEXT: icmp eq {{.*}}, null
+ // CHECK-NEXT: br i1
+ // CHECK: call void @_ZN5test11AdlEPvj(i8* %{{.*}}, i32 4)
+ delete x;
+ }
+}
+
+// Check that we make cookies for the two-arg delete even when using
+// the global allocator and deallocator.
+namespace test2 {
+ struct A {
+ int x;
+ void *operator new[](size_t);
+ void operator delete[](void *, size_t);
+ };
+
+ // CHECK: define [[A:%.*]]* @_ZN5test24testEv()
+ A *test() {
+ // CHECK: [[NEW:%.*]] = call noalias i8* @_Znaj(i32 44)
+ // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[NEW]] to i32*
+ // CHECK-NEXT: store i32 10, i32* [[T0]]
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[NEW]], i64 4
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[A]]*
+ // CHECK-NEXT: ret [[A]]* [[T2]]
+ return ::new A[10];
+ }
+
+ // CHECK: define void @_ZN5test24testEPNS_1AE(
+ void test(A *p) {
+ // CHECK: [[P:%.*]] = alloca [[A]]*, align 4
+ // CHECK-NEXT: store [[A]]* {{%.*}}, [[A]]** [[P]], align 4
+ // CHECK-NEXT: [[T0:%.*]] = load [[A]]** [[P]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = icmp eq [[A]]* [[T0]], null
+ // CHECK-NEXT: br i1 [[T1]],
+ // CHECK: [[T2:%.*]] = bitcast [[A]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 -4
+ // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i32*
+ // CHECK-NEXT: [[T5:%.*]] = load i32* [[T4]]
+ // CHECK-NEXT: call void @_ZdaPv(i8* [[T3]])
+ // CHECK-NEXT: br label
+ ::delete[] p;
+ }
+}
+
+// rdar://problem/8913519
+namespace test3 {
+ struct A {
+ int x;
+ void operator delete[](void *, size_t);
+ };
+ struct B : A {};
+
+ // CHECK: define void @_ZN5test34testEv()
+ void test() {
+ // CHECK: call noalias i8* @_Znaj(i32 24)
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: store i32 5
+ (void) new B[5];
+ }
+}
More information about the cfe-commits
mailing list