from code inspection, we were treating placement news with one argument as
non-placement news when selecting the corresponding operator delete;  this is
fixed.
Access and ambiguity control for calls to operator new and delete.  Also AFAICT



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98818 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 9251ab7..6c655e5 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2628,6 +2628,11 @@
   AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
                                            NamedDecl *D,
                                            AccessSpecifier Access);
+  AccessResult CheckAllocationAccess(SourceLocation OperatorLoc,
+                                     SourceRange PlacementRange,
+                                     CXXRecordDecl *NamingClass,
+                                     NamedDecl *Allocator,
+                                     AccessSpecifier Access);
   AccessResult CheckConstructorAccess(SourceLocation Loc,
                                       CXXConstructorDecl *D,
                                       AccessSpecifier Access);
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 6c01fee..3737c50 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -591,6 +591,24 @@
 }
                                            
 
+/// Checks access to an overloaded operator new or delete.
+Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
+                                               SourceRange PlacementRange,
+                                               CXXRecordDecl *NamingClass,
+                                               NamedDecl *Fn,
+                                               AccessSpecifier Access) {
+  if (!getLangOptions().AccessControl ||
+      !NamingClass ||
+      Access == AS_public)
+    return AR_accessible;
+
+  AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Fn);
+  Entity.setDiag(diag::err_access)
+    << PlacementRange;
+
+  return CheckAccess(*this, OpLoc, Entity);
+}
+
 /// Checks access to an overloaded member operator, including
 /// conversion operators.
 Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e1e5efa..2a55894 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -912,6 +912,8 @@
       = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
     LookupQualifiedName(FoundDelete, RD);
   }
+  if (FoundDelete.isAmbiguous())
+    return true; // FIXME: clean up expressions?
 
   if (FoundDelete.empty()) {
     DeclareGlobalNewDelete();
@@ -919,8 +921,8 @@
   }
 
   FoundDelete.suppressDiagnostics();
-  llvm::SmallVector<NamedDecl *, 4> Matches;
-  if (NumPlaceArgs > 1) {
+  UnresolvedSet<4> Matches;
+  if (NumPlaceArgs > 0) {
     // C++ [expr.new]p20:
     //   A declaration of a placement deallocation function matches the
     //   declaration of a placement allocation function if it has the
@@ -962,7 +964,7 @@
         Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
 
       if (Context.hasSameType(Fn->getType(), ExpectedFunctionType))
-        Matches.push_back(Fn);
+        Matches.addDecl(Fn, D.getAccess());
     }
   } else {
     // C++ [expr.new]p20:
@@ -973,7 +975,7 @@
          D != DEnd; ++D) {
       if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
         if (isNonPlacementDeallocationFunction(Fn))
-          Matches.push_back(*D);
+          Matches.addDecl(D.getDecl(), D.getAccess());
     }
   }
 
@@ -982,7 +984,6 @@
   //   function, that function will be called; otherwise, no
   //   deallocation function will be called.
   if (Matches.size() == 1) {
-    // FIXME: Drops access, using-declaration info!
     OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl());
 
     // C++0x [expr.new]p20:
@@ -998,6 +999,9 @@
                        PlaceArgs[NumPlaceArgs - 1]->getLocEnd());
       Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
         << DeleteName;
+    } else {
+      CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
+                            Matches[0].getDecl(), Matches[0].getAccess());
     }
   }
 
@@ -1019,7 +1023,10 @@
       << Name << Range;
   }
 
-  // FIXME: handle ambiguity
+  if (R.isAmbiguous())
+    return true;
+
+  R.suppressDiagnostics();
 
   OverloadCandidateSet Candidates(StartLoc);
   for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); 
@@ -1050,7 +1057,7 @@
     // 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.)
-    // Whatch out for variadic allocator function.
+    // Watch out for variadic allocator function.
     unsigned NumArgsInFnDecl = FnDecl->getNumParams();
     for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
       if (PerformCopyInitialization(Args[i],
@@ -1059,6 +1066,8 @@
         return true;
     }
     Operator = FnDecl;
+    CheckAllocationAccess(StartLoc, Range, R.getNamingClass(),
+                          FnDecl, Best->getAccess());
     return false;
   }
 
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index d6244aa..d101dcb 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -233,3 +233,20 @@
     }
   };
 }
+
+// Ignored operator new and delete overloads are not 
+namespace test8 {
+  typedef __typeof__(sizeof(int)) size_t;
+
+  class A {
+    void *operator new(size_t s);
+    void operator delete(void *p);
+  public:
+    void *operator new(size_t s, int n);
+    void operator delete(void *p, int n);
+  };
+
+  void test() {
+    new (2) A();
+  }
+}