summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
authorDaniel Jasper <djasper@google.com>2016-10-10 14:13:55 +0000
committerDaniel Jasper <djasper@google.com>2016-10-10 14:13:55 +0000
commite9abe648166a95a85105f4138ea41b345a66035e (patch)
tree551aed9b3cc942c9f7f0d0e95b5b02f2a0f8db04 /clang/lib/Sema/SemaExprCXX.cpp
parent610ad3a5985c1eb40917eb948f5a09266270112c (diff)
downloadbcm5719-llvm-e9abe648166a95a85105f4138ea41b345a66035e.tar.gz
bcm5719-llvm-e9abe648166a95a85105f4138ea41b345a66035e.zip
Revert "P0035R4: Semantic analysis and code generation for C++17 overaligned allocation."
This reverts commit r283722. Breaks: Clang.SemaCUDA.device-var-init.cu Clang.CodeGenCUDA.device-var-init.cu http://lab.llvm.org:8080/green/job/clang-stage1-cmake-RA-expensive/884/ llvm-svn: 283750
Diffstat (limited to 'clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp752
1 files changed, 306 insertions, 446 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 9c5dba5a38a..ad102f8d203 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/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);
OpenPOWER on IntegriCloud