From: Sebastian Redl Date: Thu, 4 Dec 2008 22:20:51 +0000 (+0000) Subject: Code cleanup in new handling. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7f6623914e779e41eb3d85f9a2dc3affea5de1e8;p=clang 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 150b32ec51..f82651bd28 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -840,6 +840,9 @@ public: 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 72ca8df5e8..1e9b945a18 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -381,128 +381,106 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, bool UseGlobal, DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); if (AllocType->isRecordType() && !UseGlobal) { - OverloadCandidateSet MemberNewCandidates; - const CXXRecordType *Record = cast( - 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(Decl)) - AddOverloadCandidate(Method, &AllocArgs[0], AllocArgs.size(), - MemberNewCandidates, - /*SuppressUserConversions=*/false); - else if (OverloadedFunctionDecl *Ovl - = dyn_cast_or_null(Decl)) { - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - if (CXXMethodDecl *Method = dyn_cast(*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(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(Decl)) - AddOverloadCandidate(Fn, &AllocArgs[0], AllocArgs.size(), - GlobalNewCandidates, - /*SuppressUserConversions=*/false); - else if (OverloadedFunctionDecl *Ovl - = dyn_cast_or_null(Decl)) { - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - if (FunctionDecl *Fn = dyn_cast(*F)) - AddOverloadCandidate(Fn, &AllocArgs[0], AllocArgs.size(), - GlobalNewCandidates, - /*SuppressUserConversions=*/false); - } - } + DeclContext *TUDecl = Context.getTranslationUnitDecl(); + if (FindAllocationOverload(StartLoc, NewName, &AllocArgs[0], + AllocArgs.size(), TUDecl, /*AllowMissing=*/false, + OperatorNew)) + return true; + } - // 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; - } + // 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; +} - 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); - return true; +/// 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; + } - case OR_Ambiguous: - // FIXME: Bad location information. - Diag(StartLoc, diag::err_ovl_ambiguous_oper) - << (IsArray ? "new[]" : "new"); - PrintOverloadCandidates(GlobalNewCandidates, /*OnlyViable=*/true); - return true; + 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(Decl)) + AddOverloadCandidate(Fn, Args, NumArgs, Candidates, + /*SuppressUserConversions=*/false); + else if (OverloadedFunctionDecl *Ovl + = dyn_cast_or_null(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); } } - AllocArgs[0]->Destroy(Context); - return 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 c90cd2f314..fa19c6a055 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -14,6 +14,9 @@ struct U // 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 @@ void good_news() 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 bad_news(int *ip) (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.