Code cleanup in new handling.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60557 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 150b32e..f82651b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -840,6 +840,9 @@
Expr **PlaceArgs, unsigned NumPlaceArgs,
FunctionDecl *&OperatorNew,
FunctionDecl *&OperatorDelete);
+ bool FindAllocationOverload(SourceLocation StartLoc, DeclarationName Name,
+ Expr** Args, unsigned NumArgs, DeclContext *Ctx,
+ bool AllowMissing, FunctionDecl *&Operator);
void DeclareGlobalNewDelete();
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
QualType Argument);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 72ca8df..1e9b945 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -381,128 +381,106 @@
DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
IsArray ? OO_Array_New : OO_New);
if (AllocType->isRecordType() && !UseGlobal) {
- OverloadCandidateSet MemberNewCandidates;
- const CXXRecordType *Record = cast<CXXRecordType>(
- AllocType->getAsRecordType());
- IdentifierResolver::iterator I =
- IdResolver.begin(NewName, Record->getDecl(), /*LookInParentCtx=*/false);
- NamedDecl *Decl = (I == IdResolver.end()) ? 0 : *I;
- // Member operator new is implicitly treated as static, so don't use
- // AddMemberCandidate.
- if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(Decl))
- AddOverloadCandidate(Method, &AllocArgs[0], AllocArgs.size(),
- MemberNewCandidates,
- /*SuppressUserConversions=*/false);
- else if (OverloadedFunctionDecl *Ovl
- = dyn_cast_or_null<OverloadedFunctionDecl>(Decl)) {
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*F))
- AddOverloadCandidate(Method, &AllocArgs[0], AllocArgs.size(),
- MemberNewCandidates,
- /*SuppressUserConversions=*/false);
- }
- }
-
- // Do the resolution.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(MemberNewCandidates, Best)) {
- case OR_Success: {
- // Got one!
- FunctionDecl *FnDecl = Best->Function;
- // The first argument is size_t, and the first parameter must be size_t,
- // too.
- for (unsigned i = 1; i < AllocArgs.size(); ++i) {
- // FIXME: Passing word to diagnostic.
- // This might modify the argument expression, so pass the one in
- // PlaceArgs.
- if (PerformCopyInitialization(PlaceArgs[i-1],
- FnDecl->getParamDecl(i)->getType(),
- "passing"))
- return true;
- }
- OperatorNew = FnDecl;
- break;
- }
-
- case OR_No_Viable_Function:
- // No viable function; look something up in the global scope instead.
- break;
-
- case OR_Ambiguous:
- // FIXME: Bad location information.
- Diag(StartLoc, diag::err_ovl_ambiguous_oper)
- << (IsArray ? "new[]" : "new");
- PrintOverloadCandidates(MemberNewCandidates, /*OnlyViable=*/true);
+ CXXRecordDecl *Record = cast<CXXRecordType>(AllocType->getAsRecordType())
+ ->getDecl();
+ // FIXME: We fail to find inherited overloads.
+ if (FindAllocationOverload(StartLoc, NewName, &AllocArgs[0],
+ AllocArgs.size(), Record, /*AllowMissing=*/true,
+ OperatorNew))
return true;
- }
}
if (!OperatorNew) {
// Didn't find a member overload. Look for a global one.
DeclareGlobalNewDelete();
- OverloadCandidateSet GlobalNewCandidates;
- IdentifierResolver::iterator I =
- IdResolver.begin(NewName, Context.getTranslationUnitDecl(),
- /*LookInParentCtx=*/false);
- NamedDecl *Decl = (I == IdResolver.end()) ? 0 : *I;
- if (FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Decl))
- AddOverloadCandidate(Fn, &AllocArgs[0], AllocArgs.size(),
- GlobalNewCandidates,
- /*SuppressUserConversions=*/false);
- else if (OverloadedFunctionDecl *Ovl
- = dyn_cast_or_null<OverloadedFunctionDecl>(Decl)) {
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*F))
- AddOverloadCandidate(Fn, &AllocArgs[0], AllocArgs.size(),
- GlobalNewCandidates,
- /*SuppressUserConversions=*/false);
- }
- }
-
- // Do the resolution.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(GlobalNewCandidates, Best)) {
- case OR_Success: {
- // Got one!
- FunctionDecl *FnDecl = Best->Function;
- // The first argument is size_t, and the first parameter must be size_t,
- // too. This is checked on declaration and can be assumed.
- for (unsigned i = 1; i < AllocArgs.size(); ++i) {
- // FIXME: Passing word to diagnostic.
- // This might modify the argument expression, so pass the one in
- // PlaceArgs.
- if (PerformCopyInitialization(PlaceArgs[i-1],
- FnDecl->getParamDecl(i)->getType(),
- "passing"))
- return true;
- }
- OperatorNew = FnDecl;
- break;
- }
-
- case OR_No_Viable_Function:
- // FIXME: Bad location information.
- Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
- << NewName << (unsigned)GlobalNewCandidates.size();
- PrintOverloadCandidates(GlobalNewCandidates, /*OnlyViable=*/false);
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ if (FindAllocationOverload(StartLoc, NewName, &AllocArgs[0],
+ AllocArgs.size(), TUDecl, /*AllowMissing=*/false,
+ OperatorNew))
return true;
-
- case OR_Ambiguous:
- // FIXME: Bad location information.
- Diag(StartLoc, diag::err_ovl_ambiguous_oper)
- << (IsArray ? "new[]" : "new");
- PrintOverloadCandidates(GlobalNewCandidates, /*OnlyViable=*/true);
- return true;
- }
}
+ // FIXME: This is leaked on error. But so much is currently in Sema that it's
+ // easier to clean it in one go.
AllocArgs[0]->Destroy(Context);
return false;
}
+/// FindAllocationOverload - Find an fitting overload for the allocation
+/// function in the specified scope.
+bool Sema::FindAllocationOverload(SourceLocation StartLoc, DeclarationName Name,
+ Expr** Args, unsigned NumArgs,
+ DeclContext *Ctx, bool AllowMissing,
+ FunctionDecl *&Operator)
+{
+ IdentifierResolver::iterator I =
+ IdResolver.begin(Name, Ctx, /*LookInParentCtx=*/false);
+ if (I == IdResolver.end()) {
+ if (AllowMissing)
+ return false;
+ // FIXME: Bad location information.
+ return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << 0;
+ }
+
+ OverloadCandidateSet Candidates;
+ NamedDecl *Decl = *I;
+ // Even member operator new/delete are implicitly treated as static, so don't
+ // use AddMemberCandidate.
+ if (FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Decl))
+ AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
+ /*SuppressUserConversions=*/false);
+ else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast_or_null<OverloadedFunctionDecl>(Decl)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if (FunctionDecl *Fn = *F)
+ AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
+ /*SuppressUserConversions=*/false);
+ }
+ }
+
+ // Do the resolution.
+ OverloadCandidateSet::iterator Best;
+ switch(BestViableFunction(Candidates, Best)) {
+ case OR_Success: {
+ // Got one!
+ FunctionDecl *FnDecl = Best->Function;
+ // The first argument is size_t, and the first parameter must be size_t,
+ // too. This is checked on declaration and can be assumed. (It can't be
+ // asserted on, though, since invalid decls are left in there.)
+ for (unsigned i = 1; i < NumArgs; ++i) {
+ // FIXME: Passing word to diagnostic.
+ if (PerformCopyInitialization(Args[i-1],
+ FnDecl->getParamDecl(i)->getType(),
+ "passing"))
+ return true;
+ }
+ Operator = FnDecl;
+ return false;
+ }
+
+ case OR_No_Viable_Function:
+ if (AllowMissing)
+ return false;
+ // FIXME: Bad location information.
+ Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << (unsigned)Candidates.size();
+ PrintOverloadCandidates(Candidates, /*OnlyViable=*/false);
+ return true;
+
+ case OR_Ambiguous:
+ // FIXME: Bad location information.
+ Diag(StartLoc, diag::err_ovl_ambiguous_call)
+ << Name;
+ PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ return true;
+ }
+ assert(false && "Unreachable, bad result from BestViableFunction");
+ return true;
+}
+
+
/// DeclareGlobalNewDelete - Declare the global forms of operator new and
/// delete. These are:
/// @code
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index c90cd2f..fa19c6a 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -14,6 +14,9 @@
// A special new, to verify that the global version isn't used.
void* operator new(size_t, S*);
};
+struct V : U
+{
+};
void* operator new(size_t); // expected-note {{candidate}}
void* operator new(size_t, int*); // expected-note {{candidate}}
@@ -34,6 +37,8 @@
ia4 *pai = new (int[3][4]);
pi = ::new int;
U *pu = new (ps) U;
+ // This is xfail. Inherited functions are not looked up currently.
+ //V *pv = new (ps) V;
}
void bad_news(int *ip)
@@ -56,7 +61,7 @@
(void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'struct S'}}
(void)::S::new int; // expected-error {{expected unqualified-id}}
(void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}}
- (void)new (0L) int; // expected-error {{use of overloaded operator 'new' is ambiguous}}
+ (void)new (0L) int; // expected-error {{call to 'operator new' is ambiguous}}
// This must fail, because the member version shouldn't be found.
(void)::new ((S*)0) U; // expected-error {{no matching function for call to 'operator new'}}
// Some lacking cases due to lack of sema support.