summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h5
-rw-r--r--include/clang/AST/ExprCXX.h16
-rw-r--r--include/clang/AST/Type.h3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--include/clang/Sema/Overload.h4
-rw-r--r--include/clang/Sema/Sema.h11
-rw-r--r--lib/AST/ASTContext.cpp24
-rw-r--r--lib/AST/ASTImporter.cpp1
-rw-r--r--lib/AST/Decl.cpp48
-rw-r--r--lib/AST/DeclCXX.cpp26
-rw-r--r--lib/AST/ExprCXX.cpp5
-rw-r--r--lib/AST/Type.cpp9
-rw-r--r--lib/CodeGen/CGExprCXX.cpp387
-rw-r--r--lib/CodeGen/CodeGenFunction.h3
-rw-r--r--lib/Sema/SemaCUDA.cpp28
-rw-r--r--lib/Sema/SemaDecl.cpp8
-rw-r--r--lib/Sema/SemaDeclCXX.cpp26
-rw-r--r--lib/Sema/SemaExprCXX.cpp752
-rw-r--r--lib/Sema/SemaOverload.cpp11
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp1
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp1
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p2.cpp19
-rw-r--r--test/CXX/expr/expr.unary/expr.delete/p10.cpp25
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p14.cpp69
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p20-0x.cpp57
-rw-r--r--test/CXX/special/class.dtor/p9.cpp19
-rw-r--r--test/CodeGenCXX/cxx1z-aligned-allocation.cpp206
27 files changed, 530 insertions, 1238 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 507d98b797..7c0d19c56f 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -1881,11 +1881,6 @@ public:
unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; }
unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).Align; }
- /// \brief Return the ABI-specified alignment of a type, in bits, or 0 if
- /// the type is incomplete and we cannot determine the alignment (for
- /// example, from alignment attributes).
- unsigned getTypeAlignIfKnown(QualType T) const;
-
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
/// characters.
CharUnits getTypeAlignInChars(QualType T) const;
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index af45b161f6..3de5cc921a 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1838,13 +1838,11 @@ class CXXNewExpr : public Expr {
unsigned GlobalNew : 1;
/// Do we allocate an array? If so, the first SubExpr is the size expression.
unsigned Array : 1;
- /// Should the alignment be passed to the allocation function?
- unsigned PassAlignment : 1;
/// If this is an array allocation, does the usual deallocation
/// function for the allocated type want to know the allocated size?
unsigned UsualArrayDeleteWantsSize : 1;
/// The number of placement new arguments.
- unsigned NumPlacementArgs : 26;
+ unsigned NumPlacementArgs : 13;
/// What kind of initializer do we have? Could be none, parens, or braces.
/// In storage, we distinguish between "none, and no initializer expr", and
/// "none, but an implicit initializer expr".
@@ -1860,8 +1858,8 @@ public:
};
CXXNewExpr(const ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
- FunctionDecl *operatorDelete, bool PassAlignment,
- bool usualArrayDeleteWantsSize, ArrayRef<Expr*> placementArgs,
+ FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
+ ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle, Expr *initializer,
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
@@ -1949,16 +1947,10 @@ public:
}
/// \brief Returns the CXXConstructExpr from this new-expression, or null.
- const CXXConstructExpr *getConstructExpr() const {
+ const CXXConstructExpr* getConstructExpr() const {
return dyn_cast_or_null<CXXConstructExpr>(getInitializer());
}
- /// Indicates whether the required alignment should be implicitly passed to
- /// the allocation function.
- bool passAlignment() const {
- return PassAlignment;
- }
-
/// Answers whether the usual array deallocation function for the
/// allocated type expects the size of the allocation as a
/// parameter.
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index fb1b50f7aa..54435502c2 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1729,8 +1729,7 @@ public:
bool isObjCARCBridgableType() const;
bool isCARCBridgableType() const;
bool isTemplateTypeParmType() const; // C++ template type parameter
- bool isNullPtrType() const; // C++11 std::nullptr_t
- bool isAlignValT() const; // C++17 std::align_val_t
+ bool isNullPtrType() const; // C++0x nullptr_t
bool isAtomicType() const; // C11 _Atomic()
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 59199aea7b..bd634a6b3a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6025,10 +6025,6 @@ def err_no_suitable_delete_member_function_found : Error<
"no suitable member %0 in %1">;
def err_ambiguous_suitable_delete_member_function_found : Error<
"multiple suitable %0 functions in %1">;
-def warn_ambiguous_suitable_delete_function_found : Warning<
- "multiple suitable %0 functions for %1; no 'operator delete' function "
- "will be invoked if initialization throws an exception">,
- InGroup<DiagGroup<"ambiguous-delete">>;
def note_member_declared_here : Note<
"member %0 declared here">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 1c2eb92789..3bcd327df9 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -795,9 +795,7 @@ namespace clang {
OverloadCandidateDisplayKind OCD,
ArrayRef<Expr *> Args,
StringRef Opc = "",
- SourceLocation Loc = SourceLocation(),
- llvm::function_ref<bool(OverloadCandidate&)> Filter =
- [](OverloadCandidate&) { return true; });
+ SourceLocation Loc = SourceLocation());
};
bool isBetterOverloadCandidate(Sema &S,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index adf7b07f14..8bd3916e0d 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4855,9 +4855,14 @@ public:
SourceRange R);
bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool UseGlobal, QualType AllocType, bool IsArray,
- bool &PassAlignment, MultiExprArg PlaceArgs,
+ MultiExprArg PlaceArgs,
FunctionDecl *&OperatorNew,
FunctionDecl *&OperatorDelete);
+ bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
+ DeclarationName Name, MultiExprArg Args,
+ DeclContext *Ctx,
+ bool AllowMissing, FunctionDecl *&Operator,
+ bool Diagnose = true);
void DeclareGlobalNewDelete();
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
ArrayRef<QualType> Params);
@@ -4867,10 +4872,7 @@ public:
bool Diagnose = true);
FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc,
bool CanProvideSize,
- bool Overaligned,
DeclarationName Name);
- FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc,
- CXXRecordDecl *RD);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
ExprResult ActOnCXXDelete(SourceLocation StartLoc,
@@ -9335,7 +9337,6 @@ public:
void EraseUnwantedCUDAMatches(
const FunctionDecl *Caller,
SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches);
- void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, LookupResult &R);
/// Given a implicit special member, infer its CUDA target from the
/// calls it needs to make to underlying base/field special members.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 6b840b9e47..dc99d4dabd 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1572,30 +1572,6 @@ bool ASTContext::isAlignmentRequired(QualType T) const {
return isAlignmentRequired(T.getTypePtr());
}
-unsigned ASTContext::getTypeAlignIfKnown(QualType T) const {
- // An alignment on a typedef overrides anything else.
- if (auto *TT = T->getAs<TypedefType>())
- if (unsigned Align = TT->getDecl()->getMaxAlignment())
- return Align;
-
- // If we have an (array of) complete type, we're done.
- T = getBaseElementType(T);
- if (!T->isIncompleteType())
- return getTypeAlign(T);
-
- // If we had an array type, its element type might be a typedef
- // type with an alignment attribute.
- if (auto *TT = T->getAs<TypedefType>())
- if (unsigned Align = TT->getDecl()->getMaxAlignment())
- return Align;
-
- // Otherwise, see if the declaration of the type had an attribute.
- if (auto *TT = T->getAs<TagType>())
- return TT->getDecl()->getMaxAlignment();
-
- return 0;
-}
-
TypeInfo ASTContext::getTypeInfo(const Type *T) const {
TypeInfoMap::iterator I = MemoizedTypeInfo.find(T);
if (I != MemoizedTypeInfo.end())
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 9e17c0c3de..d03de30d1b 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -6330,7 +6330,6 @@ Expr *ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *CE) {
Importer.getToContext(),
CE->isGlobalNew(),
OperatorNewDecl, OperatorDeleteDecl,
- CE->passAlignment(),
CE->doesUsualArrayDeleteWantSize(),
PlacementArgs,
Importer.Import(CE->getTypeIdParens()),
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e330e31d47..fec7df0ffb 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2596,7 +2596,7 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
return false;
const auto *FPT = getType()->castAs<FunctionProtoType>();
- if (FPT->getNumParams() == 0 || FPT->getNumParams() > 3 || FPT->isVariadic())
+ if (FPT->getNumParams() == 0 || FPT->getNumParams() > 2 || FPT->isVariadic())
return false;
// If this is a single-parameter function, it must be a replaceable global
@@ -2604,42 +2604,20 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
if (FPT->getNumParams() == 1)
return true;
- unsigned Params = 1;
- QualType Ty = FPT->getParamType(Params);
+ // Otherwise, we're looking for a second parameter whose type is
+ // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
+ QualType Ty = FPT->getParamType(1);
ASTContext &Ctx = getASTContext();
-
- auto Consume = [&] {
- ++Params;
- Ty = Params < FPT->getNumParams() ? FPT->getParamType(Params) : QualType();
- };
-
- // In C++14, the next parameter can be a 'std::size_t' for sized delete.
- bool IsSizedDelete = false;
if (Ctx.getLangOpts().SizedDeallocation &&
- (getDeclName().getCXXOverloadedOperator() == OO_Delete ||
- getDeclName().getCXXOverloadedOperator() == OO_Array_Delete) &&
- Ctx.hasSameType(Ty, Ctx.getSizeType())) {
- IsSizedDelete = true;
- Consume();
- }
-
- // In C++17, the next parameter can be a 'std::align_val_t' for aligned
- // new/delete.
- if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT())
- Consume();
-
- // Finally, if this is not a sized delete, the final parameter can
- // be a 'const std::nothrow_t&'.
- if (!IsSizedDelete && !Ty.isNull() && Ty->isReferenceType()) {
- Ty = Ty->getPointeeType();
- if (Ty.getCVRQualifiers() != Qualifiers::Const)
- return false;
- const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- if (RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace())
- Consume();
- }
-
- return Params == FPT->getNumParams();
+ Ctx.hasSameType(Ty, Ctx.getSizeType()))
+ return true;
+ if (!Ty->isReferenceType())
+ return false;
+ Ty = Ty->getPointeeType();
+ if (Ty.getCVRQualifiers() != Qualifiers::Const)
+ return false;
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ return RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace();
}
LanguageLinkage FunctionDecl::getLanguageLinkage() const {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 97f75a0205..d7472fcc35 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1577,35 +1577,17 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
// deallocation function. [...]
if (getNumParams() == 1)
return true;
- unsigned UsualParams = 1;
- // C++ <=14 [basic.stc.dynamic.deallocation]p2:
+ // C++ [basic.stc.dynamic.deallocation]p2:
// [...] If class T does not declare such an operator delete but does
// declare a member deallocation function named operator delete with
// exactly two parameters, the second of which has type std::size_t (18.1),
// then this function is a usual deallocation function.
- //
- // C++17 says a usual deallocation function is one with the signature
- // (void* [, size_t] [, std::align_val_t] [, ...])
- // and all such functions are usual deallocation functions. It's not clear
- // that allowing varargs functions was intentional.
ASTContext &Context = getASTContext();
- if (UsualParams < getNumParams() &&
- Context.hasSameUnqualifiedType(getParamDecl(UsualParams)->getType(),
- Context.getSizeType()))
- ++UsualParams;
-
- if (UsualParams < getNumParams() &&
- getParamDecl(UsualParams)->getType()->isAlignValT())
- ++UsualParams;
-
- if (UsualParams != getNumParams())
+ if (getNumParams() != 2 ||
+ !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(),
+ Context.getSizeType()))
return false;
-
- // In C++17 onwards, all potential usual deallocation functions are actual
- // usual deallocation functions.
- if (Context.getLangOpts().AlignedAllocation)
- return true;
// This function is a usual deallocation function if there are no
// single-parameter deallocation functions of the same kind.
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 3efb5b1cbc..a13033d474 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -62,7 +62,7 @@ SourceLocation CXXScalarValueInitExpr::getLocStart() const {
// CXXNewExpr
CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
FunctionDecl *operatorNew, FunctionDecl *operatorDelete,
- bool PassAlignment, bool usualArrayDeleteWantsSize,
+ bool usualArrayDeleteWantsSize,
ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle,
@@ -76,8 +76,7 @@ CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
SubExprs(nullptr), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens),
Range(Range), DirectInitRange(directInitRange),
- GlobalNew(globalNew), PassAlignment(PassAlignment),
- UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {
+ GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {
assert((initializer != nullptr || initializationStyle == NoInit) &&
"Only NoInit can have no initializer.");
StoredInitializationStyle = initializer ? initializationStyle + 1 : 0;
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 113974c4b6..4aa07568dc 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2337,15 +2337,6 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const {
return false;
}
-bool Type::isAlignValT() const {
- if (auto *ET = getAs<EnumType>()) {
- auto *II = ET->getDecl()->getIdentifier();
- if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace())
- return true;
- }
- return false;
-}
-
bool Type::isPromotableIntegerType() const {
if (const BuiltinType *BT = getAs<BuiltinType>())
switch (BT->getKind()) {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index ccab9f08d6..e022663788 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1219,116 +1219,111 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
llvm_unreachable("predeclared global operator new/delete is missing");
}
-static std::pair<bool, bool>
-shouldPassSizeAndAlignToUsualDelete(const FunctionProtoType *FPT) {
- auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();
+namespace {
+ /// A cleanup to call the given 'operator delete' function upon
+ /// abnormal exit from a new expression.
+ class CallDeleteDuringNew final : public EHScopeStack::Cleanup {
+ size_t NumPlacementArgs;
+ const FunctionDecl *OperatorDelete;
+ llvm::Value *Ptr;
+ llvm::Value *AllocSize;
- // The first argument is always a void*.
- ++AI;
+ RValue *getPlacementArgs() { return reinterpret_cast<RValue*>(this+1); }
- // Figure out what other parameters we should be implicitly passing.
- bool PassSize = false;
- bool PassAlignment = false;
+ public:
+ static size_t getExtraSize(size_t NumPlacementArgs) {
+ return NumPlacementArgs * sizeof(RValue);
+ }
- if (AI != AE && (*AI)->isIntegerType()) {
- PassSize = true;
- ++AI;
- }
+ CallDeleteDuringNew(size_t NumPlacementArgs,
+ const FunctionDecl *OperatorDelete,
+ llvm::Value *Ptr,
+ llvm::Value *AllocSize)
+ : NumPlacementArgs(NumPlacementArgs), OperatorDelete(OperatorDelete),
+ Ptr(Ptr), AllocSize(AllocSize) {}
- if (AI != AE && (*AI)->isAlignValT()) {
- PassAlignment = true;
- ++AI;
- }
+ void setPlacementArg(unsigned I, RValue Arg) {
+ assert(I < NumPlacementArgs && "index out of range");
+ getPlacementArgs()[I] = Arg;
+ }
- assert(AI == AE && "unexpected usual deallocation function parameter");
- return {PassSize, PassAlignment};
-}
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ const FunctionProtoType *FPT
+ = OperatorDelete->getType()->getAs<FunctionProtoType>();
+ assert(FPT->getNumParams() == NumPlacementArgs + 1 ||
+ (FPT->getNumParams() == 2 && NumPlacementArgs == 0));
-namespace {
- /// A cleanup to call the given 'operator delete' function upon abnormal
- /// exit from a new expression. Templated on a traits type that deals with
- /// ensuring that the arguments dominate the cleanup if necessary.
- template<typename Traits>
- class CallDeleteDuringNew final : public EHScopeStack::Cleanup {
- /// Type used to hold llvm::Value*s.
- typedef typename Traits::ValueTy ValueTy;
- /// Type used to hold RValues.
- typedef typename Traits::RValueTy RValueTy;
- struct PlacementArg {
- RValueTy ArgValue;
- QualType ArgType;
- };
-
- unsigned NumPlacementArgs : 31;
- unsigned PassAlignmentToPlacementDelete : 1;
+ CallArgList DeleteArgs;
+
+ // The first argument is always a void*.
+ FunctionProtoType::param_type_iterator AI = FPT->param_type_begin();
+ DeleteArgs.add(RValue::get(Ptr), *AI++);
+
+ // A member 'operator delete' can take an extra 'size_t' argument.
+ if (FPT->getNumParams() == NumPlacementArgs + 2)
+ DeleteArgs.add(RValue::get(AllocSize), *AI++);
+
+ // Pass the rest of the arguments, which must match exactly.
+ for (unsigned I = 0; I != NumPlacementArgs; ++I)
+ DeleteArgs.add(getPlacementArgs()[I], *AI++);
+
+ // Call 'operator delete'.
+ EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs);
+ }
+ };
+
+ /// A cleanup to call the given 'operator delete' function upon
+ /// abnormal exit from a new expression when the new expression is
+ /// conditional.
+ class CallDeleteDuringConditionalNew final : public EHScopeStack::Cleanup {
+ size_t NumPlacementArgs;
const FunctionDecl *OperatorDelete;
- ValueTy Ptr;
- ValueTy AllocSize;
- CharUnits AllocAlign;
+ DominatingValue<RValue>::saved_type Ptr;
+ DominatingValue<RValue>::saved_type AllocSize;
- PlacementArg *getPlacementArgs() {
- return reinterpret_cast<PlacementArg *>(this + 1);
+ DominatingValue<RValue>::saved_type *getPlacementArgs() {
+ return reinterpret_cast<DominatingValue<RValue>::saved_type*>(this+1);
}
public:
static size_t getExtraSize(size_t NumPlacementArgs) {
- return NumPlacementArgs * sizeof(PlacementArg);
+ return NumPlacementArgs * sizeof(DominatingValue<RValue>::saved_type);
}
- CallDeleteDuringNew(size_t NumPlacementArgs,
- const FunctionDecl *OperatorDelete, ValueTy Ptr,
- ValueTy AllocSize, bool PassAlignmentToPlacementDelete,
- CharUnits AllocAlign)
- : NumPlacementArgs(NumPlacementArgs),
- PassAlignmentToPlacementDelete(PassAlignmentToPlacementDelete),
- OperatorDelete(OperatorDelete), Ptr(Ptr), AllocSize(AllocSize),
- AllocAlign(AllocAlign) {}
-
- void setPlacementArg(unsigned I, RValueTy Arg, QualType Type) {
+ CallDeleteDuringConditionalNew(size_t NumPlacementArgs,
+ const FunctionDecl *OperatorDelete,
+ DominatingValue<RValue>::saved_type Ptr,
+ DominatingValue<RValue>::saved_type AllocSize)
+ : NumPlacementArgs(NumPlacementArgs), OperatorDelete(OperatorDelete),
+ Ptr(Ptr), AllocSize(AllocSize) {}
+
+ void setPlacementArg(unsigned I, DominatingValue<RValue>::saved_type Arg) {
assert(I < NumPlacementArgs && "index out of range");
- getPlacementArgs()[I] = {Arg, Type};
+ getPlacementArgs()[I] = Arg;
}
void Emit(CodeGenFunction &CGF, Flags flags) override {
- const FunctionProtoType *FPT =
- OperatorDelete->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT
+ = OperatorDelete->getType()->getAs<FunctionProtoType>();
+ assert(FPT->getNumParams() == NumPlacementArgs + 1 ||
+ (FPT->getNumParams() == 2 && NumPlacementArgs == 0));
+
CallArgList DeleteArgs;
// The first argument is always a void*.
- 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;
- 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;
- } 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);
- }
-
- // The second argument can be a std::size_t (for non-placement delete).
- if (PassSize)
- DeleteArgs.add(Traits::get(CGF, AllocSize),
- CGF.getContext().getSizeType());
+ FunctionProtoType::param_type_iterator AI = FPT->param_type_begin();
+ DeleteArgs.add(Ptr.restore(CGF), *AI++);
- // The next (second or third) argument can be a std::align_val_t, which
- // 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)
- DeleteArgs.add(RValue::get(llvm::ConstantInt::get(
- CGF.SizeTy, AllocAlign.getQuantity())),
- CGF.getContext().getSizeType());
+ // A member 'operator delete' can take an extra 'size_t' argument.
+ if (FPT->getNumParams() == NumPlacementArgs + 2) {
+ RValue RV = AllocSize.restore(CGF);
+ DeleteArgs.add(RV, *AI++);
+ }
// Pass the rest of the arguments, which must match exactly.
for (unsigned I = 0; I != NumPlacementArgs; ++I) {
- auto Arg = getPlacementArgs()[I];
- DeleteArgs.add(Traits::get(CGF, Arg.ArgValue), Arg.ArgType);
+ RValue RV = getPlacementArgs()[I].restore(CGF);
+ DeleteArgs.add(RV, *AI++);
}
// Call 'operator delete'.
@@ -1343,34 +1338,18 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
const CXXNewExpr *E,
Address NewPtr,
llvm::Value *AllocSize,
- CharUnits AllocAlign,
const CallArgList &NewArgs) {
- unsigned NumNonPlacementArgs = E->passAlignment() ? 2 : 1;
-
// If we're not inside a conditional branch, then the cleanup will
// dominate and we can do the easier (and more efficient) thing.
if (!CGF.isInConditionalBranch()) {
- struct DirectCleanupTraits {
- typedef llvm::Value *ValueTy;
- typedef RValue RValueTy;
- static RValue get(CodeGenFunction &, ValueTy V) { return RValue::get(V); }
- static RValue get(CodeGenFunction &, RValueTy V) { return V; }
- };
-
- typedef CallDeleteDuringNew<DirectCleanupTraits> DirectCleanup;
-
- DirectCleanup *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<DirectCleanup>(EHCleanup,
- E->getNumPlacementArgs(),
- E->getOperatorDelete(),
- NewPtr.getPointer(),
- AllocSize,
- E->passAlignment(),
- AllocAlign);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
- auto &Arg = NewArgs[I + NumNonPlacementArgs];
- Cleanup->setPlacementArg(I, Arg.RV, Arg.Ty);
- }
+ CallDeleteDuringNew *Cleanup = CGF.EHStack
+ .pushCleanupWithExtra<CallDeleteDuringNew>(EHCleanup,
+ E->getNumPlacementArgs(),
+ E->getOperatorDelete(),
+ NewPtr.getPointer(),
+ AllocSize);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
+ Cleanup->setPlacementArg(I, NewArgs[I+1].RV);
return;
}
@@ -1381,28 +1360,15 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
DominatingValue<RValue>::saved_type SavedAllocSize =
DominatingValue<RValue>::save(CGF, RValue::get(AllocSize));
- struct ConditionalCleanupTraits {
- typedef DominatingValue<RValue>::saved_type ValueTy;
- typedef DominatingValue<RValue>::saved_type RValueTy;
- static RValue get(CodeGenFunction &CGF, ValueTy V) {
- return V.restore(CGF);
- }
- };
- typedef CallDeleteDuringNew<ConditionalCleanupTraits> ConditionalCleanup;
-
- ConditionalCleanup *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<ConditionalCleanup>(EHCleanup,
- E->getNumPlacementArgs(),
- E->getOperatorDelete(),
- SavedNewPtr,
- SavedAllocSize,
- E->passAlignment(),
- AllocAlign);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
- auto &Arg = NewArgs[I + NumNonPlacementArgs];
- Cleanup->setPlacementArg(I, DominatingValue<RValue>::save(CGF, Arg.RV),
- Arg.Ty);
- }
+ CallDeleteDuringConditionalNew *Cleanup = CGF.EHStack
+ .pushCleanupWithExtra<CallDeleteDuringConditionalNew>(EHCleanup,
+ E->getNumPlacementArgs(),
+ E->getOperatorDelete(),
+ SavedNewPtr,
+ SavedAllocSize);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
+ Cleanup->setPlacementArg(I,
+ DominatingValue<RValue>::save(CGF, NewArgs[I+1].RV));
CGF.initFullExprCleanup();
}
@@ -1431,7 +1397,6 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::Value *allocSize =
EmitCXXNewAllocSize(*this, E, minElements, numElements,
allocSizeWithoutCookie);
- CharUnits allocAlign = getContext().getTypeAlignInChars(allocType);
// Emit the allocation call. If the allocator is a global placement
// operator, just "inline" it directly.
@@ -1447,8 +1412,10 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// The pointer expression will, in many cases, be an opaque void*.
// In these cases, discard the computed alignment and use the
// formal alignment of the allocated type.
- if (alignSource != AlignmentSource::Decl)
- allocation = Address(allocation.getPointer(), allocAlign);
+ if (alignSource != AlignmentSource::Decl) {
+ allocation = Address(allocation.getPointer(),
+ getContext().getTypeAlignInChars(allocType));
+ }
// Set up allocatorArgs for the call to operator delete if it's not
// the reserved global operator.
@@ -1461,55 +1428,28 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
} else {
const FunctionProtoType *allocatorType =
allocator->getType()->castAs<FunctionProtoType>();
- unsigned ParamsToSkip = 0;
// The allocation size is the first argument.
QualType sizeType = getContext().getSizeType();
allocatorArgs.add(RValue::get(allocSize), sizeType);
- ++ParamsToSkip;
-
- if (allocSize != allocSizeWithoutCookie) {
- CharUnits cookieAlign = getSizeAlign(); // FIXME: Ask the ABI.
- allocAlign = std::max(allocAlign, cookieAlign);
- }
-
- // The allocation alignment may be passed as the second argument.
- if (E->passAlignment()) {
- QualType AlignValT = sizeType;
- if (allocatorType->getNumParams() > 1) {
- AlignValT = allocatorType->getParamType(1);
- assert(getContext().hasSameUnqualifiedType(
- AlignValT->castAs<EnumType>()->getDecl()->getIntegerType(),
- sizeType) &&
- "wrong type for alignment parameter");
- ++ParamsToSkip;
- } else {
- // Corner case, passing alignment to 'operator new(size_t, ...)'.
- assert(allocator->isVariadic() && "can't pass alignment to allocator");
- }
- allocatorArgs.add(
- RValue::get(llvm::ConstantInt::get(SizeTy, allocAlign.getQuantity())),
- AlignValT);
- }
- // FIXME: Why do we not pass a CalleeDecl here?
+ // We start at 1 here because the first argument (the allocation size)
+ // has already been emitted.
EmitCallArgs(allocatorArgs, allocatorType, E->placement_arguments(),
- /*CalleeDecl*/nullptr, /*ParamsToSkip*/ParamsToSkip);
+ /* CalleeDecl */ nullptr,
+ /*ParamsToSkip*/ 1);
RValue RV =
EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
- // If this was a call to a global replaceable allocation function that does
- // not take an alignment argument, the allocator is known to produce
- // storage that's suitably aligned for any object that fits, up to a known
- // threshold. Otherwise assume it's suitably aligned for the allocated type.
- CharUnits allocationAlign = allocAlign;
- if (!E->passAlignment() &&
- allocator->isReplaceableGlobalAllocationFunction()) {
- unsigned AllocatorAlign = llvm::PowerOf2Floor(std::min<uint64_t>(
- Target.getNewAlign(), getContext().getTypeSize(allocType)));
- allocationAlign = std::max(
- allocationAlign, getContext().toCharUnitsFromBits(AllocatorAlign));
+ // For now, only assume that the allocation function returns
+ // something satisfactorily aligned for the element type, plus
+ // the cookie if we have one.
+ CharUnits allocationAlign =
+ getContext().getTypeAlignInChars(allocType);
+ if (allocSize != allocSizeWithoutCookie) {
+ CharUnits cookieAlign = getSizeAlign(); // FIXME?
+ allocationAlign = std::max(allocationAlign, cookieAlign);
}
allocation = Address(RV.getScalarVal(), allocationAlign);
@@ -1548,8 +1488,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::Instruction *cleanupDominator = nullptr;
if (E->getOperatorDelete() &&
!E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
- EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocAlign,
- allocatorArgs);
+ EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs);
operatorDeleteCleanup = EHStack.stable_begin();
cleanupDominator = Builder.CreateUnreachable();
}
@@ -1611,58 +1550,31 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
}
void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
- llvm::Value *Ptr, QualType DeleteTy,
- llvm::Value *NumElements,
- CharUnits CookieSize) {
- assert((!NumElements && CookieSize.isZero()) ||
- DeleteFD->getOverloadedOperator() == OO_Array_Delete);
+ llvm::Value *Ptr,
+ QualType DeleteTy) {
+ assert(DeleteFD->getOverloadedOperator() == OO_Delete);
const FunctionProtoType *DeleteFTy =
DeleteFD->getType()->getAs<FunctionProtoType>();
CallArgList DeleteArgs;
- std::pair<bool, bool> PassSizeAndAlign =
- shouldPassSizeAndAlignToUsualDelete(DeleteFTy);
-
- auto ParamTypeIt = DeleteFTy->param_type_begin();
-
- // Pass the pointer itself.
- QualType ArgTy = *ParamTypeIt++;
- llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
- DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
-
- // Pass the size if the delete function has a size_t parameter.
- if (PassSizeAndAlign.first) {
- QualType SizeType = *ParamTypeIt++;
+ // Check if we need to pass the size to the delete operator.
+ llvm::Value *Size = nullptr;
+ QualType SizeTy;
+ if (DeleteFTy->getNumParams() == 2) {
+ SizeTy = DeleteFTy->getParamType(1);
CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
- llvm::Value *Size = llvm::ConstantInt::get(ConvertType(SizeType),
- DeleteTypeSize.getQuantity());
-
- // For array new, multiply by the number of elements.
- if (NumElements)
- Size = Builder.CreateMul(Size, NumElements);
-
- // If there is a cookie, add the cookie size.
- if (!CookieSize.isZero())
- Size = Builder.CreateAdd(
- Size, llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()));
-
- DeleteArgs.add(RValue::get(Size), SizeType);
+ Size = llvm::ConstantInt::get(ConvertType(SizeTy),
+ DeleteTypeSize.getQuantity());
}
- // Pass the alignment if the delete function has an align_val_t parameter.
- if (PassSizeAndAlign.second) {
- QualType AlignValType = *ParamTypeIt++;
- CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits(
- getContext().getTypeAlignIfKnown(DeleteTy));
- llvm::Value *Align = llvm::ConstantInt::get(ConvertType(AlignValType),
- DeleteTypeAlign.getQuantity());
- DeleteArgs.add(RValue::get(Align), AlignValType);
- }
+ QualType ArgTy = DeleteFTy->getParamType(0);
+ llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
+ DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
- assert(ParamTypeIt == DeleteFTy->param_type_end() &&
- "unknown parameter to usual delete function");
+ if (Size)
+ DeleteArgs.add(RValue::get(Size), SizeTy);
// Emit the call to delete.
EmitNewDeleteCall(*this, DeleteFD, DeleteFTy, DeleteArgs);
@@ -1766,8 +1678,45 @@ namespace {
ElementType(ElementType), CookieSize(CookieSize) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType, NumElements,
- CookieSize);
+ const FunctionProtoType *DeleteFTy =
+ OperatorDelete->getType()->getAs<FunctionProtoType>();
+ assert(DeleteFTy->getNumParams() == 1 || DeleteFTy->getNumParams() == 2);
+
+ CallArgList Args;
+
+ // Pass the pointer as the first argument.
+ QualType VoidPtrTy = DeleteFTy->getParamType(0);
+ llvm::Value *DeletePtr
+ = CGF.Builder.CreateBitCast(Ptr, CGF.ConvertType(VoidPtrTy));
+ Args.add(RValue::get(DeletePtr), VoidPtrTy);
+
+ // Pass the original requested size as the second argument.
+ if (DeleteFTy->getNumParams() == 2) {
+ QualType size_t = DeleteFTy->getParamType(1);
+ llvm::IntegerType *SizeTy
+ = cast<llvm::IntegerType>(CGF.ConvertType(size_t));
+
+ CharUnits ElementTypeSize =
+ CGF.CGM.getContext().getTypeSizeInChars(ElementType);
+
+ // The size of an element, multiplied by the number of elements.
+ llvm::Value *Size
+ = llvm::ConstantInt::get(SizeTy, ElementTypeSize.getQuantity());
+ if (NumElements)
+ Size = CGF.Builder.CreateMul(Size, NumElements);
+
+ // Plus the size of the cookie if applicable.
+ if (!CookieSize.isZero()) {
+ llvm::Value *CookieSizeV
+ = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity());
+ Size = CGF.Builder.CreateAdd(Size, CookieSizeV);
+ }
+
+ Args.add(RValue::get(Size), size_t);
+ }
+
+ // Emit the call to delete.
+ EmitNewDeleteCall(CGF, OperatorDelete, DeleteFTy, Args);
}
};
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index eac759fc82..4e149e65dc 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -2033,8 +2033,7 @@ public:
void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr,
- QualType DeleteTy, llvm::Value *NumElements = nullptr,
- CharUnits CookieSize = CharUnits());
+ QualType DeleteTy);
RValue EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
const Expr *Arg, bool IsDelete);
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index 827eb02bcd..d6c0606674 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -158,34 +158,6 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
llvm_unreachable("All cases should've been handled by now.");
}
-void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller,
- LookupResult &R) {
- if (R.isSingleResult())
- return;
-
- // Gets the CUDA function preference for a call from Caller to Match.
- auto GetCFP = [&](const NamedDecl *D) {
- if (auto *Callee = dyn_cast<FunctionDecl>(D->getUnderlyingDecl()))
- return IdentifyCUDAPreference(Caller, Callee);
- return CFP_Never;
- };
-
- // Find the best call preference among the functions in R.
- CUDAFunctionPreference BestCFP = GetCFP(*std::max_element(
- R.begin(), R.end(), [&](const NamedDecl *D1, const NamedDecl *D2) {
- return GetCFP(D1) < GetCFP(D2);
- }));
-
- // Erase all functions with lower priority.
- auto Filter = R.makeFilter();
- while (Filter.hasNext()) {
- auto *Callee = dyn_cast<FunctionDecl>(Filter.next()->getUnderlyingDecl());
- if (Callee && GetCFP(Callee) < BestCFP)
- Filter.erase();
- }
- Filter.done();
-}
-
template <typename T>
static void EraseUnwantedCUDAMatchesImpl(
Sema &S, const FunctionDecl *Caller, llvm::SmallVectorImpl<T> &Matches,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7baa85a646..32201c99d3 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14368,14 +14368,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (!Completed)
Record->completeDefinition();
- // We may have deferred checking for a deleted destructor. Check now.
- if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
- auto *Dtor = CXXRecord->getDestructor();
- if (Dtor && Dtor->isImplicit() &&
- ShouldDeleteSpecialMember(Dtor, CXXDestructor))
- SetDeclDeleted(Dtor, CXXRecord->getLocation());
- }
-
if (Record->hasAttrs()) {
CheckAlignasUnderalignment(Record);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 36a0338d4a..0f7f0ffa75 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -6755,7 +6755,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name,
- OperatorDelete, /*Diagnose*/false)) {
+ OperatorDelete, false)) {
if (Diagnose)
Diag(RD->getLocation(), diag::note_deleted_dtor_no_operator_delete);
return true;
@@ -7695,11 +7695,19 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
Loc = RD->getLocation();
// If we have a virtual destructor, look up the deallocation function
- if (FunctionDecl *OperatorDelete =
- FindDeallocationFunctionForDestructor(Loc, RD)) {
- MarkFunctionReferenced(Loc, OperatorDelete);
- Destructor->setOperatorDelete(OperatorDelete);
- }
+ FunctionDecl *OperatorDelete = nullptr;
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
+ return true;
+ // If there's no class-specific operator delete, look up the global
+ // non-array delete.
+ if (!OperatorDelete)
+ OperatorDelete = FindUsualDeallocationFunction(Loc, true, Name);
+
+ MarkFunctionReferenced(Loc, OperatorDelete);
+
+ Destructor->setOperatorDelete(OperatorDelete);
}
return false;
@@ -10272,11 +10280,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, Destructor);
- // We can't check whether an implicit destructor is deleted before we complete
- // the definition of the class, because its validity depends on the alignment
- // of the class. We'll check this from ActOnFields once the class is complete.
- if (ClassDecl->isCompleteDefinition() &&
- ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
SetDeclDeleted(Destructor, ClassLoc);
// Introduce this destructor into its scope.
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 9c5dba5a38..ad102f8d20 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1321,126 +1321,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
return Result;
}
-/// \brief Determine whether the given function is a non-placement
-/// deallocation function.
-static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
- if (FD->isInvalidDecl())
- return false;
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
- return Method->isUsualDeallocationFunction();
-
- if (FD->getOverloadedOperator() != OO_Delete &&
- FD->getOverloadedOperator() != OO_Array_Delete)
- return false;
-
- unsigned UsualParams = 1;
-
- if (S.getLangOpts().SizedDeallocation && UsualParams < FD->getNumParams() &&
- S.Context.hasSameUnqualifiedType(
- FD->getParamDecl(UsualParams)->getType(),
- S.Context.getSizeType()))
- ++UsualParams;
-
- if (S.getLangOpts().AlignedAllocation && UsualParams < FD->getNumParams() &&
- S.Context.hasSameUnqualifiedType(
- FD->getParamDecl(UsualParams)->getType(),
- S.Context.getTypeDeclType(S.getStdAlignValT())))
- ++UsualParams;
-
- return UsualParams == FD->getNumParams();
-}
-
-namespace {
- struct UsualDeallocFnInfo {
- UsualDeallocFnInfo() : Found(), FD(nullptr) {}
- UsualDeallocFnInfo(DeclAccessPair Found)
- : Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())),
- HasSizeT(false), HasAlignValT(false) {
- // A function template declaration is never a usual deallocation function.
- if (!FD)
- return;
- if (FD->getNumParams() == 3)
- HasAlignValT = HasSizeT = true;
- else if (FD->getNumParams() == 2) {
- HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType();
- HasAlignValT = !HasSizeT;
- }
- }
-
- operator bool() const { return FD; }
-
- DeclAccessPair Found;
- FunctionDecl *FD;
- bool HasSizeT, HasAlignValT;
- };
-}
-
-/// Determine whether a type has new-extended alignment. This may be called when
-/// the type is incomplete (for a delete-expression with an incomplete pointee
-/// type), in which case it will conservatively return false if the alignment is
-/// not known.
-static bool hasNewExtendedAlignment(Sema &S, QualType AllocType) {
- return S.getLangOpts().AlignedAllocation &&
- S.getASTContext().getTypeAlignIfKnown(AllocType) >
- S.getASTContext().getTargetInfo().getNewAlign();
-}
-
-/// Select the correct "usual" deallocation function to use from a selection of
-/// deallocation functions (either global or class-scope).
-static UsualDeallocFnInfo resolveDeallocationOverload(
- Sema &S, LookupResult &R, bool WantSize, bool WantAlign,
- llvm::SmallVectorImpl<UsualDeallocFnInfo> *BestFns = nullptr) {
- UsualDeallocFnInfo Best;
-
- // For CUDA, rank callability above anything else when ordering usual
- // deallocation functions.
- // FIXME: We should probably instead rank this between alignment (which
- // affects correctness) and size (which is just an optimization).
- if (S.getLangOpts().CUDA)
- S.EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(S.CurContext), R);
-
- for (auto I = R.begin(), E = R.end(); I != E; ++I) {
- UsualDeallocFnInfo Info(I.getPair());
- if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD))
- continue;
-
- if (!Best) {
- Best = Info;
- if (BestFns)
- BestFns->push_back(Info);
- continue;
- }
-
- // C++17 [expr.delete]p10:
- // If the type has new-extended alignment, a function with a parameter of
- // type std::align_val_t is preferred; otherwise a function without such a
- // parameter is preferred
- if (Best.HasAlignValT == WantAlign && Info.HasAlignValT != WantAlign)
- continue;
-
- if (Best.HasAlignValT == Info.HasAlignValT &&
- Best.HasSizeT == WantSize && Info.HasSizeT != WantSize)
- continue;
-
- // If more than one preferred function is found, all non-preferred
- // functions are eliminated from further consideration.
- if (BestFns && (Best.HasAlignValT != Info.HasAlignValT ||
- Best.HasSizeT != Info.HasSizeT))
- BestFns->clear();
-
- Best = Info;
- if (BestFns)
- BestFns->push_back(Info);
- }
-
- return Best;
-}
-
-/// Determine whether a given type is a class for which 'delete[]' would call
-/// a member 'operator delete[]' with a 'size_t' parameter. This implies that
-/// we need to store the array size (even if the type is
-/// trivially-destructible).
+/// 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 =
@@ -1464,13 +1346,35 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
// on this thing, so it doesn't matter if we allocate extra space or not.
if (ops.isAmbiguous()) return false;
- // C++17 [expr.delete]p10:
- // If the deallocation functions have class scope, the one without a
- // parameter of type std::size_t is selected.
- auto Best = resolveDeallocationOverload(
- S, ops, /*WantSize*/false,
- /*WantAlign*/hasNewExtendedAlignment(S, allocType));
- return Best && Best.HasSizeT;
+ 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);
}
/// \brief Parsed a C++ 'new' expression (C++ 5.3.4).
@@ -1826,26 +1730,21 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
FunctionDecl *OperatorNew = nullptr;
FunctionDecl *OperatorDelete = nullptr;
- unsigned Alignment =
- AllocType->isDependentType() ? 0 : Context.getTypeAlign(AllocType);
- unsigned NewAlignment = Context.getTargetInfo().getNewAlign();
- bool PassAlignment = getLangOpts().AlignedAllocation &&
- Alignment > NewAlignment;
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
FindAllocationFunctions(StartLoc,
SourceRange(PlacementLParen, PlacementRParen),
- UseGlobal, AllocType, ArraySize, PassAlignment,
- PlacementArgs, OperatorNew, OperatorDelete))
+ UseGlobal, AllocType, ArraySize, PlacementArgs,
+ 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);
+ UsualArrayDeleteWantsSize
+ = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType);
SmallVector<Expr *, 8> AllPlaceArgs;
if (OperatorNew) {
@@ -1856,11 +1755,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// We've already converted the placement args, just fill in any default
// arguments. Skip the first parameter because we don't have a corresponding
- // argument. Skip the second parameter too if we're passing in the
- // alignment; we've already filled it in.
- if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto,
- PassAlignment ? 2 : 1, PlacementArgs,
- AllPlaceArgs, CallType))
+ // argument.
+ if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1,
+ PlacementArgs, AllPlaceArgs, CallType))
return ExprError();
if (!AllPlaceArgs.empty())
@@ -1870,18 +1767,21 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs);
// FIXME: Missing call to CheckFunctionCall or equivalent
+ }
- // Warn if the type is over-aligned and is being allocated by (unaligned)
- // global operator new.
- if (PlacementArgs.empty() && !PassAlignment &&
- (OperatorNew->isImplicit() ||
- (OperatorNew->getLocStart().isValid() &&
- getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) {
- if (Alignment > NewAlignment)
+ // Warn if the type is over-aligned and is being allocated by global operator
+ // new.
+ if (PlacementArgs.empty() && OperatorNew &&
+ (OperatorNew->isImplicit() ||
+ (OperatorNew->getLocStart().isValid() &&
+ getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) {
+ if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){
+ unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign();
+ if (Align > SuitableAlign)
Diag(StartLoc, diag::warn_overaligned_type)
<< AllocType
- << unsigned(Alignment / Context.getCharWidth())
- << unsigned(NewAlignment / Context.getCharWidth());
+ << unsigned(Align / Context.getCharWidth())
+ << unsigned(SuitableAlign / Context.getCharWidth());
}
}
@@ -1980,7 +1880,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
return new (Context)
- CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, PassAlignment,
+ CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete,
UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens,
ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo,
Range, DirectInitRange);
@@ -2023,128 +1923,32 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
return false;
}
-static bool
-resolveAllocationOverload(Sema &S, LookupResult &R, SourceRange Range,
- SmallVectorImpl<Expr *> &Args, bool &PassAlignment,
- FunctionDecl *&Operator,
- OverloadCandidateSet *AlignedCandidates = nullptr,
- Expr *AlignArg = nullptr) {
- OverloadCandidateSet Candidates(R.getNameLoc(),
- OverloadCandidateSet::CSK_Normal);
- for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
- Alloc != AllocEnd; ++Alloc) {
- // Even member operator new/delete are implicitly treated as
- // static, so don't use AddMemberCandidate.
- NamedDecl *D = (*Alloc)->getUnderlyingDecl();
-
- if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
- S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
- /*ExplicitTemplateArgs=*/nullptr, Args,
- Candidates,
- /*SuppressUserConversions=*/false);
- continue;
- }
-
- FunctionDecl *Fn = cast<FunctionDecl>(D);
- S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates,
- /*SuppressUserConversions=*/false);
- }
-
- // Do the resolution.
- OverloadCandidateSet::iterator Best;
- switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) {
- case OR_Success: {
- // Got one!
- FunctionDecl *FnDecl = Best->Function;
- if (S.CheckAllocationAccess(R.getNameLoc(), Range, R.getNamingClass(),
- Best->FoundDecl) == Sema::AR_inaccessible)
- return true;
-
- Operator = FnDecl;
+/// \brief Determine whether the given function is a non-placement
+/// deallocation function.
+static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
+ if (FD->isInvalidDecl())
return false;
- }
- case OR_No_Viable_Function:
- // C++17 [expr.new]p13:
- // If no matching function is found and the allocated object type has
- // new-extended alignment, the alignment argument is removed from the
- // argument list, and overload resolution is performed again.
- if (PassAlignment) {
- PassAlignment = false;
- AlignArg = Args[1];
- Args.erase(Args.begin() + 1);
- return resolveAllocationOverload(S, R, Range, Args, PassAlignment,
- Operator, &Candidates, AlignArg);
- }
-
- // MSVC will fall back on trying to find a matching global operator new
- // if operator new[] cannot be found. Also, MSVC will leak by not
- // generating a call to operator delete or operator delete[], but we
- // will not replicate that bug.
- // FIXME: Find out how this interacts with the std::align_val_t fallback
- // once MSVC implements it.
- if (R.getLookupName().getCXXOverloadedOperator() == OO_Array_New &&
- S.Context.getLangOpts().MSVCCompat) {
- R.clear();
- R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New));
- S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl());
- // FIXME: This will give bad diagnostics pointing at the wrong functions.
- return resolveAllocationOverload(S, R, Range, Args, PassAlignment,
- Operator, nullptr);
- }
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
+ return Method->isUsualDeallocationFunction();
- S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
- << R.getLookupName() << Range;
-
- // If we have aligned candidates, only note the align_val_t candidates
- // from AlignedCandidates and the non-align_val_t candidates from
- // Candidates.
- if (AlignedCandidates) {
- auto IsAligned = [](OverloadCandidate &C) {
- return C.Function->getNumParams() > 1 &&
- C.Function->getParamDecl(1)->getType()->isAlignValT();
- };
- auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); };
-
- // This was an overaligned allocation, so list the aligned candidates
- // first.
- Args.insert(Args.begin() + 1, AlignArg);
- AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "",
- R.getNameLoc(), IsAligned);
- Args.erase(Args.begin() + 1);
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(),
- IsUnaligned);
- } else {
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
- }
- return true;
+ if (FD->getOverloadedOperator() != OO_Delete &&
+ FD->getOverloadedOperator() != OO_Array_Delete)
+ return false;
- case OR_Ambiguous:
- S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call)
- << R.getLookupName() << Range;
- Candidates.NoteCandidates(S, OCD_ViableCandidates, Args);
+ if (FD->getNumParams() == 1)
return true;
- case OR_Deleted: {
- S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call)
- << Best->Function->isDeleted()
- << R.getLookupName()
- << S.getDeletedOrUnavailableSuffix(Best->Function)
- << Range;
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
- return true;
- }
- }
- llvm_unreachable("Unreachable, bad result from BestViableFunction");
+ return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 &&
+ S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(),
+ S.Context.getSizeType());
}
-
/// FindAllocationFunctions - Finds the overloads of operator new and delete
/// that are appropriate for the allocation.
bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool UseGlobal, QualType AllocType,
- bool IsArray, bool &PassAlignment,
- MultiExprArg PlaceArgs,
+ bool IsArray, MultiExprArg PlaceArgs,
FunctionDecl *&OperatorNew,
FunctionDecl *&OperatorDelete) {
// --- Choosing an allocation function ---
@@ -2156,29 +1960,16 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 3) The first argument is always size_t. Append the arguments from the
// placement form.
- SmallVector<Expr*, 8> AllocArgs;
- AllocArgs.reserve((PassAlignment ? 2 : 1) + PlaceArgs.size());
-
- // We don't care about the actual value of these arguments.
+ SmallVector<Expr*, 8> AllocArgs(1 + PlaceArgs.size());
+ // We don't care about the actual value of this argument.
// FIXME: Should the Sema create the expression and embed it in the syntax
// tree? Or should the consumer just recalculate the value?
- // FIXME: Using a dummy value will interact poorly with attribute enable_if.
IntegerLiteral Size(Context, llvm::APInt::getNullValue(
Context.getTargetInfo().getPointerWidth(0)),
Context.getSizeType(),
SourceLocation());
- AllocArgs.push_back(&Size);
-
- QualType AlignValT = Context.VoidTy;
- if (PassAlignment) {
- DeclareGlobalNewDelete();
- AlignValT = Context.getTypeDeclType(getStdAlignValT());
- }
- CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation());
- if (PassAlignment)
- AllocArgs.push_back(&Align);
-
- AllocArgs.insert(AllocArgs.end(), PlaceArgs.begin(), PlaceArgs.end());
+ AllocArgs[0] = &Size;
+ std::copy(PlaceArgs.begin(), PlaceArgs.end(), AllocArgs.begin() + 1);
// C++ [expr.new]p8:
// If the allocated type is a non-array type, the allocation
@@ -2187,57 +1978,50 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// type, the allocation function's name is operator new[] and the
// deallocation function's name is operator delete[].
DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
- IsArray ? OO_Array_New : OO_New);
+ IsArray ? OO_Array_New : OO_New);
+ DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
+ IsArray ? OO_Array_Delete : OO_Delete);
QualType AllocElemType = Context.getBaseElementType(AllocType);
- // Find the allocation function.
- {
- LookupResult R(*this, NewName, StartLoc, LookupOrdinaryName);
-
- // C++1z [expr.new]p9:
- // If the new-expression begins with a unary :: operator, the allocation
- // function's name is looked up in the global scope. Otherwise, if the
- // allocated type is a class type T or array thereof, the allocation
- // function's name is looked up in the scope of T.
- if (AllocElemType->isRecordType() && !UseGlobal)
- LookupQualifiedName(R, AllocElemType->getAsCXXRecordDecl());
-
- // We can see ambiguity here if the allocation function is found in
- // multiple base classes.
- if (R.isAmbiguous())
+ if (AllocElemType->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl());
+ if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, Record,
+ /*AllowMissing=*/true, OperatorNew))
return true;
+ }
- // If this lookup fails to find the name, or if the allocated type is not
- // a class type, the allocation function's name is looked up in the
- // global scope.
- if (R.empty())
- LookupQualifiedName(R, Context.getTranslationUnitDecl());
-
- assert(!R.empty() && "implicitly declared allocation functions not found");
- assert(!R.isAmbiguous() && "global allocation functions are ambiguous");
-
- // We do our own custom access checks below.
- R.suppressDiagnostics();
+ if (!OperatorNew) {
+ // Didn't find a member overload. Look for a global one.
+ DeclareGlobalNewDelete();
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ bool FallbackEnabled = IsArray && Context.getLangOpts().MSVCCompat;
+ if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl,
+ /*AllowMissing=*/FallbackEnabled, OperatorNew,
+ /*Diagnose=*/!FallbackEnabled)) {
+ if (!FallbackEnabled)
+ return true;
- if (resolveAllocationOverload(*this, R, Range, AllocArgs, PassAlignment,
- OperatorNew))
+ // MSVC will fall back on trying to find a matching global operator new
+ // if operator new[] cannot be found. Also, MSVC will leak by not
+ // generating a call to operator delete or operator delete[], but we
+ // will not replicate that bug.
+ NewName = Context.DeclarationNames.getCXXOperatorName(OO_New);
+ DeleteName = Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl,
+ /*AllowMissing=*/false, OperatorNew))
return true;
+ }
}
- // We don't need an operator delete if we're running under -fno-exceptions.
+ // We don't need an operator delete if we're running under
+ // -fno-exceptions.
if (!getLangOpts().Exceptions) {
OperatorDelete = nullptr;
return false;
}
- // Note, the name of OperatorNew might have been changed from array to
- // non-array by resolveAllocationOverload.
- DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
- OperatorNew->getDeclName().getCXXOverloadedOperator() == OO_Array_New
- ? OO_Array_Delete
- : OO_Delete);
-
// C++ [expr.new]p19:
//
// If the new-expression begins with a unary :: operator, the
@@ -2256,7 +2040,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
if (FoundDelete.isAmbiguous())
return true; // FIXME: clean up expressions?
- bool FoundGlobalDelete = FoundDelete.empty();
if (FoundDelete.empty()) {
DeclareGlobalNewDelete();
LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl());
@@ -2271,16 +2054,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// we had explicit placement arguments. This matters for things like
// struct A { void *operator new(size_t, int = 0); ... };
// A *a = new A()
- //
- // We don't have any definition for what a "placement allocation function"
- // is, but we assume it's any allocation function whose
- // parameter-declaration-clause is anything other than (size_t).
- //
- // FIXME: Should (size_t, std::align_val_t) also be considered non-placement?
- // This affects whether an exception from the constructor of an overaligned
- // type uses the sized or non-sized form of aligned operator delete.
- bool isPlacementNew = !PlaceArgs.empty() || OperatorNew->param_size() != 1 ||
- OperatorNew->isVariadic();
+ bool isPlacementNew = (!PlaceArgs.empty() || OperatorNew->param_size() != 1);
if (isPlacementNew) {
// C++ [expr.new]p20:
@@ -2306,9 +2080,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
ArgTypes.push_back(Proto->getParamType(I));
FunctionProtoType::ExtProtoInfo EPI;
- // FIXME: This is not part of the standard's rule.
EPI.Variadic = Proto->isVariadic();
- EPI.ExceptionSpec.Type = EST_BasicNoexcept;
ExpectedFunctionType
= Context.getFunctionType(Context.VoidTy, ArgTypes, EPI);
@@ -2332,29 +2104,35 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
if (Context.hasSameType(Fn->getType(), ExpectedFunctionType))
Matches.push_back(std::make_pair(D.getPair(), Fn));
}
-
- if (getLangOpts().CUDA)
- EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches);
} else {
+ // C++ [expr.new]p20:
+ // [...] Any non-placement deallocation function matches a
+ // non-placement allocation function. [...]
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
+ if (isNonPlacementDeallocationFunction(*this, Fn))
+ Matches.push_back(std::make_pair(D.getPair(), Fn));
+ }
+
// C++1y [expr.new]p22:
// For a non-placement allocation function, the normal deallocation
// function lookup is used
- //
- // Per [expr.delete]p10, this lookup prefers a member operator delete
- // without a size_t argument, but prefers a non-member operator delete
- // with a size_t where possible (which it always is in this case).
- llvm::SmallVector<UsualDeallocFnInfo, 4> BestDeallocFns;
- UsualDeallocFnInfo Selected = resolveDeallocationOverload(
- *this, FoundDelete, /*WantSize*/ FoundGlobalDelete,
- /*WantAlign*/ hasNewExtendedAlignment(*this, AllocElemType),
- &BestDeallocFns);
- if (Selected)
- Matches.push_back(std::make_pair(Selected.Found, Selected.FD));
- else {
- // If we failed to select an operator, all remaining functions are viable
- // but ambiguous.
- for (auto Fn : BestDeallocFns)
- Matches.push_back(std::make_pair(Fn.Found, Fn.FD));
+ // C++1y [expr.delete]p?:
+ // If [...] deallocation function lookup finds both a usual deallocation
+ // function with only a pointer parameter and a usual deallocation
+ // function with both a pointer parameter and a size parameter, then the
+ // selected deallocation function shall be the one with two parameters.
+ // Otherwise, the selected deallocation function shall be the function
+ // with one parameter.
+ if (getLangOpts().SizedDeallocation && Matches.size() == 2) {
+ if (Matches[0].second->getNumParams() == 1)
+ Matches.erase(Matches.begin());
+ else
+ Matches.erase(Matches.begin() + 1);
+ assert(Matches[0].second->getNumParams() == 2 &&
+ "found an unexpected usual deallocation function");
}
}
@@ -2365,58 +2143,130 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
if (Matches.size() == 1) {
OperatorDelete = Matches[0].second;
- // C++1z [expr.new]p23:
- // If the lookup finds a usual deallocation function (3.7.4.2)
- // with a parameter of type std::size_t and that function, considered
+ // C++0x [expr.new]p20:
+ // If the lookup finds the two-parameter form of a usual
+ // deallocation function (3.7.4.2) and that function, considered
// as a placement deallocation function, would have been
// selected as a match for the allocation function, the program
// is ill-formed.
- if (getLangOpts().CPlusPlus11 && isPlacementNew &&
+ if (!PlaceArgs.empty() && getLangOpts().CPlusPlus11 &&
isNonPlacementDeallocationFunction(*this, OperatorDelete)) {
- UsualDeallocFnInfo Info(DeclAccessPair::make(OperatorDelete, AS_public));
- // Core issue, per mail to core reflector, 2016-10-09:
- // If this is a member operator delete, and there is a corresponding
- // non-sized member operator delete, this isn't /really/ a sized
- // deallocation function, it just happens to have a size_t parameter.
- bool IsSizedDelete = Info.HasSizeT;
- if (IsSizedDelete && !FoundGlobalDelete) {
- auto NonSizedDelete =
- resolveDeallocationOverload(*this, FoundDelete, /*WantSize*/false,
- /*WantAlign*/Info.HasAlignValT);
- if (NonSizedDelete && !NonSizedDelete.HasSizeT &&
- NonSizedDelete.HasAlignValT == Info.HasAlignValT)
- IsSizedDelete = false;
- }
+ Diag(StartLoc, diag::err_placement_new_non_placement_delete)
+ << SourceRange(PlaceArgs.front()->getLocStart(),
+ PlaceArgs.back()->getLocEnd());
+ if (!OperatorDelete->isImplicit())
+ Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
+ << DeleteName;
+ } else {
+ CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
+ Matches[0].first);
+ }
+ }
- if (IsSizedDelete) {
- SourceRange R = PlaceArgs.empty()
- ? SourceRange()
- : SourceRange(PlaceArgs.front()->getLocStart(),
- PlaceArgs.back()->getLocEnd());
- Diag(StartLoc, diag::err_placement_new_non_placement_delete) << R;
- if (!OperatorDelete->isImplicit())
- Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
- << DeleteName;
- }
+ return false;
+}
+
+/// \brief Find an fitting overload for the allocation function
+/// in the specified scope.
+///
+/// \param StartLoc The location of the 'new' token.
+/// \param Range The range of the placement arguments.
+/// \param Name The name of the function ('operator new' or 'operator new[]').
+/// \param Args The placement arguments specified.
+/// \param Ctx The scope in which we should search; either a class scope or the
+/// translation unit.
+/// \param AllowMissing If \c true, report an error if we can't find any
+/// allocation functions. Otherwise, succeed but don't fill in \p
+/// Operator.
+/// \param Operator Filled in with the found allocation function. Unchanged if
+/// no allocation function was found.
+/// \param Diagnose If \c true, issue errors if the allocation function is not
+/// usable.
+bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
+ DeclarationName Name, MultiExprArg Args,
+ DeclContext *Ctx,
+ bool AllowMissing, FunctionDecl *&Operator,
+ bool Diagnose) {
+ LookupResult R(*this, Name, StartLoc, LookupOrdinaryName);
+ LookupQualifiedName(R, Ctx);
+ if (R.empty()) {
+ if (AllowMissing || !Diagnose)
+ return false;
+ return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << Range;
+ }
+
+ if (R.isAmbiguous())
+ return true;
+
+ R.suppressDiagnostics();
+
+ OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal);
+ for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
+ Alloc != AllocEnd; ++Alloc) {
+ // Even member operator new/delete are implicitly treated as
+ // static, so don't use AddMemberCandidate.
+ NamedDecl *D = (*Alloc)->getUnderlyingDecl();
+
+ if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
+ AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
+ /*ExplicitTemplateArgs=*/nullptr,
+ Args, Candidates,
+ /*SuppressUserConversions=*/false);
+ continue;
}
- CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
- Matches[0].first);
- } else if (!Matches.empty()) {
- // We found multiple suitable operators. Per [expr.new]p20, that means we
- // call no 'operator delete' function, but we should at least warn the user.
- // FIXME: Suppress this warning if the construction cannot throw.
- Diag(StartLoc, diag::warn_ambiguous_suitable_delete_function_found)
- << DeleteName << AllocElemType;
+ FunctionDecl *Fn = cast<FunctionDecl>(D);
+ AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates,
+ /*SuppressUserConversions=*/false);
+ }
- for (auto &Match : Matches)
- Diag(Match.second->getLocation(),
- diag::note_member_declared_here) << DeleteName;
+ // Do the resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (Candidates.BestViableFunction(*this, StartLoc, Best)) {
+ case OR_Success: {
+ // Got one!
+ FunctionDecl *FnDecl = Best->Function;
+ if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(),
+ Best->FoundDecl, Diagnose) == AR_inaccessible)
+ return true;
+
+ Operator = FnDecl;
+ return false;
}
- return false;
+ case OR_No_Viable_Function:
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << Range;
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args);
+ }
+ return true;
+
+ case OR_Ambiguous:
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_ambiguous_call)
+ << Name << Range;
+ Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args);
+ }
+ return true;
+
+ case OR_Deleted: {
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_deleted_call)
+ << Best->Function->isDeleted()
+ << Name
+ << getDeletedOrUnavailableSuffix(Best->Function)
+ << Range;
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args);
+ }
+ return true;
+ }
+ }
+ llvm_unreachable("Unreachable, bad result from BestViableFunction");
}
+
/// DeclareGlobalNewDelete - Declare the global forms of operator new and
/// delete. These are:
/// @code
@@ -2610,43 +2460,52 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
bool CanProvideSize,
- bool Overaligned,
DeclarationName Name) {
DeclareGlobalNewDelete();
LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName);
LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl());
- // FIXME: It's possible for this to result in ambiguity, through a
- // user-declared variadic operator delete or the enable_if attribute. We
- // should probably not consider those cases to be usual deallocation
- // functions. But for now we just make an arbitrary choice in that case.
- auto Result = resolveDeallocationOverload(*this, FoundDelete, CanProvideSize,
- Overaligned);
- assert(Result.FD && "operator delete missing from global scope?");
- return Result.FD;
-}
+ // C++ [expr.new]p20:
+ // [...] Any non-placement deallocation function matches a
+ // non-placement allocation function. [...]
+ llvm::SmallVector<FunctionDecl*, 2> Matches;
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*D))
+ if (isNonPlacementDeallocationFunction(*this, Fn))
+ Matches.push_back(Fn);
+ }
+
+ // C++1y [expr.delete]p?:
+ // If the type is complete and deallocation function lookup finds both a
+ // usual deallocation function with only a pointer parameter and a usual
+ // deallocation function with both a pointer parameter and a size
+ // parameter, then the selected deallocation function shall be the one
+ // with two parameters. Otherwise, the selected deallocation function
+ // shall be the function with one parameter.
+ if (getLangOpts().SizedDeallocation && Matches.size() == 2) {
+ unsigned NumArgs = CanProvideSize ? 2 : 1;
+ if (Matches[0]->getNumParams() != NumArgs)
+ Matches.erase(Matches.begin());
+ else
+ Matches.erase(Matches.begin() + 1);
+ assert(Matches[0]->getNumParams() == NumArgs &&
+ "found an unexpected usual deallocation function");
+ }
-FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc,
- CXXRecordDecl *RD) {
- DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (getLangOpts().CUDA)
+ EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches);
- FunctionDecl *OperatorDelete = nullptr;
- if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
- return nullptr;
- if (OperatorDelete)
- return OperatorDelete;
-
- // If there's no class-specific operator delete, look up the global
- // non-array delete.
- return FindUsualDeallocationFunction(
- Loc, true, hasNewExtendedAlignment(*this, Context.getRecordType(RD)),
- Name);
+ assert(Matches.size() == 1 &&
+ "unexpectedly have multiple usual deallocation functions");
+ return Matches.front();
}
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
- FunctionDecl *&Operator, bool Diagnose) {
+ FunctionDecl* &Operator, bool Diagnose) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
@@ -2656,20 +2515,27 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Found.suppressDiagnostics();
- bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD));
+ SmallVector<DeclAccessPair,4> Matches;
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F) {
+ NamedDecl *ND = (*F)->getUnderlyingDecl();
- // C++17 [expr.delete]p10:
- // If the deallocation functions have class scope, the one without a
- // parameter of type std::size_t is selected.
- llvm::SmallVector<UsualDeallocFnInfo, 4> Matches;
- resolveDeallocationOverload(*this, Found, /*WantSize*/ false,
- /*WantAlign*/ Overaligned, &Matches);
+ // Ignore template operator delete members from the check for a usual
+ // deallocation function.
+ if (isa<FunctionTemplateDecl>(ND))
+ continue;
+
+ if (cast<CXXMethodDecl>(ND)->isUsualDeallocationFunction())
+ Matches.push_back(F.getPair());
+ }
- // If we could find an overload, use it.
+ if (getLangOpts().CUDA)
+ EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches);
+
+ // There's exactly one suitable operator; pick it.
if (Matches.size() == 1) {
- Operator = cast<CXXMethodDecl>(Matches[0].FD);
+ Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl());
- // FIXME: DiagnoseUseOfDecl?
if (Operator->isDeleted()) {
if (Diagnose) {
Diag(StartLoc, diag::err_deleted_function_use);
@@ -2679,21 +2545,21 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
}
if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
- Matches[0].Found, Diagnose) == AR_inaccessible)
+ Matches[0], Diagnose) == AR_inaccessible)
return true;
return false;
- }
- // We found multiple suitable operators; complain about the ambiguity.
- // FIXME: The standard doesn't say to do this; it appears that the intent
- // is that this should never happen.
- if (!Matches.empty()) {
+ // We found multiple suitable operators; complain about the ambiguity.
+ } else if (!Matches.empty()) {
if (Diagnose) {
Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
<< Name << RD;
- for (auto &Match : Matches)
- Diag(Match.FD->getLocation(), diag::note_member_declared_here) << Name;
+
+ for (SmallVectorImpl<DeclAccessPair>::iterator
+ F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
+ Diag((*F)->getUnderlyingDecl()->getLocation(),
+ diag::note_member_declared_here) << Name;
}
return true;
}
@@ -2705,8 +2571,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
<< Name << RD;
- for (NamedDecl *D : Found)
- Diag(D->getUnderlyingDecl()->getLocation(),
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F)
+ Diag((*F)->getUnderlyingDecl()->getLocation(),
diag::note_member_declared_here) << Name;
}
return true;
@@ -3117,10 +2984,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// Otherwise, the usual operator delete[] should be the
// function we just found.
else if (OperatorDelete && isa<CXXMethodDecl>(OperatorDelete))
- UsualArrayDeleteWantsSize =
- UsualDeallocFnInfo(
- DeclAccessPair::make(OperatorDelete, AS_public))
- .HasSizeT;
+ UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
}
if (!PointeeRD->hasIrrelevantDestructor())
@@ -3137,17 +3001,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
SourceLocation());
}
- if (!OperatorDelete) {
- bool IsComplete = isCompleteType(StartLoc, Pointee);
- bool CanProvideSize =
- IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize ||
- Pointee.isDestructedType());
- bool Overaligned = hasNewExtendedAlignment(*this, Pointee);
-
+ if (!OperatorDelete)
// Look for a global declaration.
- OperatorDelete = FindUsualDeallocationFunction(StartLoc, CanProvideSize,
- Overaligned, DeleteName);
- }
+ OperatorDelete = FindUsualDeallocationFunction(
+ StartLoc, isCompleteType(StartLoc, Pointee) &&
+ (!ArrayForm || UsualArrayDeleteWantsSize ||
+ Pointee.isDestructedType()),
+ DeleteName);
MarkFunctionReferenced(StartLoc, OperatorDelete);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 082a6f98ef..7ca85a907e 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -10142,17 +10142,16 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
/// PrintOverloadCandidates - When overload resolution fails, prints
/// diagnostic messages containing the candidates in the candidate
/// set.
-void OverloadCandidateSet::NoteCandidates(
- Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args,
- StringRef Opc, SourceLocation OpLoc,
- llvm::function_ref<bool(OverloadCandidate &)> Filter) {
+void OverloadCandidateSet::NoteCandidates(Sema &S,
+ OverloadCandidateDisplayKind OCD,
+ ArrayRef<Expr *> Args,
+ StringRef Opc,
+ SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
// be prohibitive, so we make a set of pointers and sort those.
SmallVector<OverloadCandidate*, 32> Cands;
if (OCD == OCD_AllCandidates) Cands.reserve(size());
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
- if (!Filter(*Cand))
- continue;
if (Cand->Viable)
Cands.push_back(Cand);
else if (OCD == OCD_AllCandidates) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index a87a054f11..28d83c7e81 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1410,7 +1410,6 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
E->GlobalNew = Record[Idx++];
bool isArray = Record[Idx++];
- E->PassAlignment = Record[Idx++];
E->UsualArrayDeleteWantsSize = Record[Idx++];
unsigned NumPlacementArgs = Record[Idx++];
E->StoredInitializationStyle = Record[Idx++];
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index ddb69d966a..8e7cb64e50 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1392,7 +1392,6 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
Record.push_back(E->isGlobalNew());
Record.push_back(E->isArray());
- Record.push_back(E->passAlignment());
Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->getNumPlacementArgs());
Record.push_back(E->StoredInitializationStyle);
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p2.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p2.cpp
deleted file mode 100644
index 9e3210c665..0000000000
--- a/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p2.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clang_cc1 -std=c++1z -fsized-deallocation -fexceptions -verify %s
-
-using size_t = decltype(sizeof(0));
-
-namespace std { enum class align_val_t : size_t {}; }
-
-// p2 says "A template instance is never a usual deallocation function,
-// regardless of its signature." We (and every other implementation) assume
-// this means "A function template specialization [...]"
-template<typename...Ts> struct A {
- void *operator new(size_t);
- void operator delete(void*, Ts...) = delete; // expected-note 4{{deleted}}
-};
-
-auto *a1 = new A<>; // expected-error {{deleted}}
-auto *a2 = new A<size_t>; // expected-error {{deleted}}
-auto *a3 = new A<std::align_val_t>; // expected-error {{deleted}}
-auto *a4 = new A<size_t, std::align_val_t>; // expected-error {{deleted}}
-auto *a5 = new A<std::align_val_t, size_t>; // ok, not usual
diff --git a/test/CXX/expr/expr.unary/expr.delete/p10.cpp b/test/CXX/expr/expr.unary/expr.delete/p10.cpp
deleted file mode 100644
index aad2747dd3..0000000000
--- a/test/CXX/expr/expr.unary/expr.delete/p10.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clang_cc1 -std=c++1z -verify %s
-
-using size_t = decltype(sizeof(0));
-namespace std { enum class align_val_t : size_t {}; }
-
-// Aligned version is preferred over unaligned version,
-// unsized version is preferred over sized version.
-template<unsigned Align>
-struct alignas(Align) A {
- void operator delete(void*);
- void operator delete(void*, std::align_val_t) = delete; // expected-note {{here}}
-
- void operator delete(void*, size_t) = delete;
- void operator delete(void*, size_t, std::align_val_t) = delete;
-};
-void f(A<__STDCPP_DEFAULT_NEW_ALIGNMENT__> *p) { delete p; }
-void f(A<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2> *p) { delete p; } // expected-error {{deleted}}
-
-template<unsigned Align>
-struct alignas(Align) B {
- void operator delete(void*, size_t);
- void operator delete(void*, size_t, std::align_val_t) = delete; // expected-note {{here}}
-};
-void f(B<__STDCPP_DEFAULT_NEW_ALIGNMENT__> *p) { delete p; }
-void f(B<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2> *p) { delete p; } // expected-error {{deleted}}
diff --git a/test/CXX/expr/expr.unary/expr.new/p14.cpp b/test/CXX/expr/expr.unary/expr.new/p14.cpp
deleted file mode 100644
index 6537cdcfea..0000000000
--- a/test/CXX/expr/expr.unary/expr.new/p14.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// RUN: %clang_cc1 -std=c++1z -fsized-deallocation -fexceptions %s -verify
-
-using size_t = decltype(sizeof(0));
-namespace std { enum class align_val_t : size_t {}; }
-
-struct Arg {} arg;
-
-// If the type is aligned, first try with an alignment argument and then
-// without. If not, never consider supplying an alignment.
-
-template<unsigned Align, typename ...Ts>
-struct alignas(Align) Unaligned {
- void *operator new(size_t, Ts...) = delete; // expected-note 4{{deleted}}
-};
-auto *ua = new Unaligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // expected-error {{deleted}}
-auto *ub = new Unaligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2>; // expected-error {{deleted}}
-auto *uap = new (arg) Unaligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__, Arg>; // expected-error {{deleted}}
-auto *ubp = new (arg) Unaligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2, Arg>; // expected-error {{deleted}}
-
-template<unsigned Align, typename ...Ts>
-struct alignas(Align) Aligned {
- void *operator new(size_t, std::align_val_t, Ts...) = delete; // expected-note 2{{deleted}} expected-note 2{{not viable}}
-};
-auto *aa = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // expected-error {{no matching}}
-auto *ab = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2>; // expected-error {{deleted}}
-auto *aap = new (arg) Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__, Arg>; // expected-error {{no matching}}
-auto *abp = new (arg) Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2, Arg>; // expected-error {{deleted}}
-
-// If both are available, we prefer the aligned version for an overaligned
-// type, and only use the unaligned version for a non-overaligned type.
-
-template<unsigned Align, typename ...Ts>
-struct alignas(Align) Both1 {
- void *operator new(size_t, Ts...); // expected-note 2{{not viable}}
- void *operator new(size_t, std::align_val_t, Ts...) = delete; // expected-note 2{{deleted}}
-};
-template<unsigned Align, typename ...Ts>
-struct alignas(Align) Both2 {
- void *operator new(size_t, Ts...) = delete; // expected-note 2{{deleted}}
- void *operator new(size_t, std::align_val_t, Ts...); // expected-note 2{{not viable}}
-};
-auto *b1a = new Both1<__STDCPP_DEFAULT_NEW_ALIGNMENT__>;
-auto *b1b = new Both1<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2>; // expected-error {{deleted}}
-auto *b2a = new Both2<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // expected-error {{deleted}}
-auto *b2b = new Both2<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2>;
-auto *b1ap = new (arg) Both1<__STDCPP_DEFAULT_NEW_ALIGNMENT__, Arg>;
-auto *b1bp = new (arg) Both1<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2, Arg>; // expected-error {{deleted}}
-auto *b2ap = new (arg) Both2<__STDCPP_DEFAULT_NEW_ALIGNMENT__, Arg>; // expected-error {{deleted}}
-auto *b2bp = new (arg) Both2<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2, Arg>;
-
-// Note that the aligned form can select a function with a parameter different
-// from std::align_val_t.
-
-struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) WeirdAlignedAlloc1 {
- void *operator new(size_t, ...) = delete; // expected-note 2{{deleted}}
-};
-auto *waa1 = new WeirdAlignedAlloc1; // expected-error {{deleted}}
-auto *waa1p = new (arg) WeirdAlignedAlloc1; // expected-error {{deleted}}
-
-struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) WeirdAlignedAlloc2 {
- template<typename ...T>
- void *operator new(size_t, T...) {
- using U = void(T...); // expected-note 2{{previous}}
- using U = void; // expected-error {{different types ('void' vs 'void (std::align_val_t)')}} \
- expected-error {{different types ('void' vs 'void (std::align_val_t, Arg)')}}
- }
-};
-auto *waa2 = new WeirdAlignedAlloc2; // expected-note {{instantiation of}}
-auto *waa2p = new (arg) WeirdAlignedAlloc2; // expected-note {{instantiation of}}
diff --git a/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp b/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
index 13676a8a07..eca1ec7901 100644
--- a/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
@@ -1,10 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fexceptions %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -fexceptions %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z -fexceptions %s
typedef __SIZE_TYPE__ size_t;
-namespace std { enum class align_val_t : size_t {}; }
-
struct S {
// Placement allocation function:
static void* operator new(size_t, size_t);
@@ -13,56 +9,5 @@ struct S {
};
void testS() {
- S* p = new (0) S; // expected-error{{'new' expression with placement arguments refers to non-placement 'operator delete'}}
-}
-
-struct T {
- // Placement allocation function:
- static void* operator new(size_t, size_t);
- // Usual (non-placement) deallocation function:
- static void operator delete(void*);
- // Placement deallocation function:
- static void operator delete(void*, size_t);
-};
-
-void testT() {
- T* p = new (0) T; // ok
-}
-
-#if __cplusplus > 201402L
-struct U {
- // Placement allocation function:
- static void* operator new(size_t, size_t, std::align_val_t);
- // Placement deallocation function:
- static void operator delete(void*, size_t, std::align_val_t); // expected-note{{declared here}}
-};
-
-void testU() {
- U* p = new (0, std::align_val_t(0)) U; // expected-error{{'new' expression with placement arguments refers to non-placement 'operator delete'}}
-}
-
-struct V {
- // Placement allocation function:
- static void* operator new(size_t, size_t, std::align_val_t);
- // Usual (non-placement) deallocation function:
- static void operator delete(void*, std::align_val_t);
- // Placement deallocation function:
- static void operator delete(void*, size_t, std::align_val_t);
-};
-
-void testV() {
- V* p = new (0, std::align_val_t(0)) V;
-}
-
-struct W {
- // Placement allocation function:
- static void* operator new(size_t, size_t, std::align_val_t);
- // Usual (non-placement) deallocation functions:
- static void operator delete(void*);
- static void operator delete(void*, size_t, std::align_val_t); // expected-note {{declared here}}
-};
-
-void testW() {
- W* p = new (0, std::align_val_t(0)) W; // expected-error{{'new' expression with placement arguments refers to non-placement 'operator delete'}}
+ S* p = new (0) S; // expected-error{{'new' expression with placement arguments refers to non-placement 'operator delete'}}
}
-#endif
diff --git a/test/CXX/special/class.dtor/p9.cpp b/test/CXX/special/class.dtor/p9.cpp
index 4c6fbf4343..cfde48b0aa 100644
--- a/test/CXX/special/class.dtor/p9.cpp
+++ b/test/CXX/special/class.dtor/p9.cpp
@@ -31,13 +31,13 @@ namespace test0 {
namespace test1 {
class A {
public:
- static void operator delete(void *p) {};
+ static void operator delete(void *p) {}; // expected-note {{member 'operator delete' declared here}}
virtual ~A();
};
class B : protected A {
public:
- static void operator delete(void *, size_t) {};
+ static void operator delete(void *, size_t) {}; // expected-note {{member 'operator delete' declared here}}
~B();
};
@@ -49,20 +49,7 @@ namespace test1 {
~C();
};
- // We assume that the intent is to treat C::operator delete(void*, size_t) as
- // /not/ being a usual deallocation function, as it would be if it were
- // declared with in C directly.
- C::~C() {}
-
- struct D {
- void operator delete(void*); // expected-note {{member 'operator delete' declared here}}
- void operator delete(void*, ...); // expected-note {{member 'operator delete' declared here}}
- virtual ~D();
- };
- // FIXME: The standard doesn't say this is ill-formed, but presumably either
- // it should be or the variadic operator delete should not be a usual
- // deallocation function.
- D::~D() {} // expected-error {{multiple suitable 'operator delete' functions in 'D'}}
+ C::~C() {} // expected-error {{multiple suitable 'operator delete' functions in 'C'}}
}
// ...at the point of definition of a virtual destructor...
diff --git a/test/CodeGenCXX/cxx1z-aligned-allocation.cpp b/test/CodeGenCXX/cxx1z-aligned-allocation.cpp
deleted file mode 100644
index 437597d963..0000000000
--- a/test/CodeGenCXX/cxx1z-aligned-allocation.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-// Check that delete exprs call aligned (de)allocation functions if
-// -faligned-allocation is passed in both C++11 and C++14.
-// RUN: %clang_cc1 -std=c++11 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c++14 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
-
-// Check that we don't used aligned (de)allocation without -faligned-allocation or C++1z.
-// RUN: %clang_cc1 -std=c++14 -DUNALIGNED -fexceptions %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED
-// RUN: %clang_cc1 -std=c++1z -DUNALIGNED -fexceptions -fno-aligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED
-
-// CHECK-UNALIGNED-NOT: _Znwm_St11align_val_t
-// CHECK-UNALIGNED-NOT: _Znam_St11align_val_t
-// CHECK-UNALIGNED-NOT: _ZdlPv_St11align_val_t
-// CHECK-UNALIGNED-NOT: _ZdaPv_St11align_val_t
-// CHECK-UNALIGNED-NOT: _ZdlPvm_St11align_val_t
-// CHECK-UNALIGNED-NOT: _ZdaPvm_St11align_val_t
-
-typedef decltype(sizeof(0)) size_t;
-namespace std { enum class align_val_t : size_t {}; }
-
-#define OVERALIGNED alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2)
-
-// Global new and delete.
-// ======================
-struct OVERALIGNED A { A(); int n[128]; };
-
-// CHECK-LABEL: define {{.*}} @_Z2a0v()
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZnwmSt11align_val_t(i64 512, i64 32)
-// CHECK: call void @_ZdlPvSt11align_val_t(i8* %[[ALLOC]], i64 32)
-void *a0() { return new A; }
-
-// CHECK-LABEL: define {{.*}} @_Z2a1l(
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZnamSt11align_val_t(i64 %{{.*}}, i64 32)
-// No array cookie.
-// CHECK-NOT: store
-// CHECK: invoke void @_ZN1AC1Ev(
-// CHECK: call void @_ZdaPvSt11align_val_t(i8* %[[ALLOC]], i64 32)
-void *a1(long n) { return new A[n]; }
-
-// CHECK-LABEL: define {{.*}} @_Z2a2P1A(
-// CHECK: call void @_ZdlPvmSt11align_val_t(i8* %{{.*}}, i64 512, i64 32) #9
-void a2(A *p) { delete p; }
-
-// CHECK-LABEL: define {{.*}} @_Z2a3P1A(
-// CHECK: call void @_ZdaPvSt11align_val_t(i8* %{{.*}}, i64 32) #9
-void a3(A *p) { delete[] p; }
-
-
-// Class-specific usual new and delete.
-// ====================================
-struct OVERALIGNED B {
- B();
- // These are just a distraction. We should ignore them.
- void *operator new(size_t);
- void operator delete(void*, size_t);
- void operator delete[](void*, size_t);
-
- void *operator new(size_t, std::align_val_t);
- void operator delete(void*, std::align_val_t);
- void operator delete[](void*, std::align_val_t);
-
- int n[128];
-};
-
-// CHECK-LABEL: define {{.*}} @_Z2b0v()
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZN1BnwEmSt11align_val_t(i64 512, i64 32)
-// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* %[[ALLOC]], i64 32)
-void *b0() { return new B; }
-
-// CHECK-LABEL: define {{.*}} @_Z2b1l(
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZnamSt11align_val_t(i64 %{{.*}}, i64 32)
-// No array cookie.
-// CHECK-NOT: store
-// CHECK: invoke void @_ZN1BC1Ev(
-// CHECK: call void @_ZN1BdaEPvSt11align_val_t(i8* %[[ALLOC]], i64 32)
-void *b1(long n) { return new B[n]; }
-
-// CHECK-LABEL: define {{.*}} @_Z2b2P1B(
-// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* %{{.*}}, i64 32)
-void b2(B *p) { delete p; }
-
-// CHECK-LABEL: define {{.*}} @_Z2b3P1B(
-// CHECK: call void @_ZN1BdaEPvSt11align_val_t(i8* %{{.*}}, i64 32)
-void b3(B *p) { delete[] p; }
-
-struct OVERALIGNED C {
- C();
- void *operator new[](size_t, std::align_val_t);
- void operator delete[](void*, size_t, std::align_val_t);
-
- // It doesn't matter that we have an unaligned operator delete[] that doesn't
- // want the size. What matters is that the aligned one does.
- void operator delete[](void*);
-};
-
-// This one has an array cookie.
-// CHECK-LABEL: define {{.*}} @_Z2b4l(
-// CHECK: call {{.*}} @llvm.umul.with.overflow{{.*}}i64 32
-// CHECK: call {{.*}} @llvm.uadd.with.overflow{{.*}}i64 32
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZN1CnaEmSt11align_val_t(i64 %{{.*}}, i64 32)
-// CHECK: store
-// CHECK: call void @_ZN1CC1Ev(
-//
-// Note, we're still calling a placement allocation function, and there is no
-// matching placement operator delete. =(
-// FIXME: This seems broken.
-// CHECK-NOT: call void @_ZN1CdaEPvmSt11align_val_t(
-#ifndef UNALIGNED
-void *b4(long n) { return new C[n]; }
-#endif
-
-// CHECK-LABEL: define {{.*}} @_Z2b5P1C(
-// CHECK: mul i64{{.*}} 32
-// CHECK: add i64{{.*}} 32
-// CHECK: call void @_ZN1CdaEPvmSt11align_val_t(
-void b5(C *p) { delete[] p; }
-
-
-// Global placement new.
-// =====================
-
-struct Q { int n; } q;
-void *operator new(size_t, Q);
-void *operator new(size_t, std::align_val_t, Q);
-void operator delete(void*, Q);
-void operator delete(void*, std::align_val_t, Q);
-
-// CHECK-LABEL: define {{.*}} @_Z2c0v(
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZnwmSt11align_val_t1Q(i64 512, i64 32, i32 %
-// CHECK: call void @_ZdlPvSt11align_val_t1Q(i8* %[[ALLOC]], i64 32, i32 %
-void *c0() { return new (q) A; }
-
-
-// Class-specific placement new.
-// =============================
-
-struct OVERALIGNED D {
- D();
- void *operator new(size_t, Q);
- void *operator new(size_t, std::align_val_t, Q);
- void operator delete(void*, Q);
- void operator delete(void*, std::align_val_t, Q);
-};
-
-// CHECK-LABEL: define {{.*}} @_Z2d0v(
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZN1DnwEmSt11align_val_t1Q(i64 32, i64 32, i32 %
-// CHECK: call void @_ZN1DdlEPvSt11align_val_t1Q(i8* %[[ALLOC]], i64 32, i32 %
-void *d0() { return new (q) D; }
-
-
-// Calling aligned new with placement syntax.
-// ==========================================
-
-#ifndef UNALIGNED
-// CHECK-LABEL: define {{.*}} @_Z2e0v(
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZnwmSt11align_val_t(i64 512, i64 5)
-// CHECK: call void @_ZdlPvSt11align_val_t(i8* %[[ALLOC]], i64 5)
-void *e0() { return new (std::align_val_t(5)) A; }
-
-// CHECK-LABEL: define {{.*}} @_Z2e1v(
-// CHECK: %[[ALLOC:.*]] = call i8* @_ZN1BnwEmSt11align_val_t(i64 512, i64 5)
-// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* %[[ALLOC]], i64 5)
-void *e1() { return new (std::align_val_t(5)) B; }
-#endif
-
-// Variadic placement/non-placement allocation functions.
-// ======================================================
-
-struct OVERALIGNED F {
- F();
- void *operator new(size_t, ...);
- void operator delete(void*, ...);
- int n[128];
-};
-
-// CHECK-LABEL: define {{.*}} @_Z2f0v(
-// CHECK: %[[ALLOC:.*]] = call i8* (i64, ...) @_ZN1FnwEmz(i64 512, i64 32)
-// Non-placement allocation function, uses normal deallocation lookup which
-// cares about whether a parameter has type std::align_val_t.
-// CHECK: call void (i8*, ...) @_ZN1FdlEPvz(i8* %[[ALLOC]])
-void *f0() { return new F; }
-
-// CHECK-LABEL: define {{.*}} @_Z2f1v(
-// CHECK: %[[ALLOC:.*]] = call i8* (i64, ...) @_ZN1FnwEmz(i64 512, i64 32, i32 %
-// Placement allocation function, uses placement deallocation matching, which
-// passes same arguments and therefore includes alignment.
-// CHECK: call void (i8*, ...) @_ZN1FdlEPvz(i8* %[[ALLOC]], i64 32, i32 %
-void *f1() { return new (q) F; }
-
-struct OVERALIGNED G {
- G();
- void *operator new(size_t, std::align_val_t, ...);
- void operator delete(void*, std::align_val_t, ...);
- int n[128];
-};
-#ifndef UNALIGNED
-// CHECK-LABEL: define {{.*}} @_Z2g0v
-// CHECK: %[[ALLOC:.*]] = call i8* (i64, i64, ...) @_ZN1GnwEmSt11align_val_tz(i64 512, i64 32)
-// CHECK: call void (i8*, i64, ...) @_ZN1GdlEPvSt11align_val_tz(i8* %[[ALLOC]], i64 32)
-void *g0() { return new G; }
-
-// CHECK-LABEL: define {{.*}} @_Z2g1v
-// CHECK: %[[ALLOC:.*]] = call i8* (i64, i64, ...) @_ZN1GnwEmSt11align_val_tz(i64 512, i64 32, i32 %
-// CHECK: call void (i8*, i64, ...) @_ZN1GdlEPvSt11align_val_tz(i8* %[[ALLOC]], i64 32, i32 %
-void *g1() { return new (q) G; }
-#endif