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.