]> granicus.if.org Git - clang/commitdiff
Look through using declarations when deciding whether to use an operator
authorJohn McCall <rjmccall@apple.com>
Wed, 4 Aug 2010 00:31:26 +0000 (00:31 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 4 Aug 2010 00:31:26 +0000 (00:31 +0000)
delete for a virtual destructor.  Diagnose ambiguities.

Fixes PR7803.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110173 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExprCXX.cpp
test/CXX/special/class.dtor/p9.cpp [new file with mode: 0644]

index ef59f985dbf8d7d6ecbe7cde7eb1e510cd915a18..470261425a97f625da483a433d12ea4d36dc0694 100644 (file)
@@ -2400,6 +2400,8 @@ def err_delete_incomplete_class_type : Warning<
   "deleting incomplete class type %0; no conversions to pointer type">;
 def err_no_suitable_delete_member_function_found : Error<
   "no suitable member %0 in %1">;
+def err_ambiguous_suitable_delete_member_function_found : Error<
+  "multiple suitable %0 functions in %1">;
 def note_member_declared_here : Note<
   "member %0 declared here">;
 def err_decrement_bool : Error<"cannot decrement expression of type bool">;
index 8b2fc7e56a1ede4adb6d8ea9942204e8227add76..6d28dbdc12af9c4240d11418cca3a77c87386c6c 100644 (file)
@@ -1298,15 +1298,31 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
 
   Found.suppressDiagnostics();
 
+  llvm::SmallVector<DeclAccessPair,4> Matches;
   for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
        F != FEnd; ++F) {
-    if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
-      if (Delete->isUsualDeallocationFunction()) {
-        Operator = Delete;
-        CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
-                              F.getPair());
-        return false;
-      }
+    CXXMethodDecl *Delete = cast<CXXMethodDecl>((*F)->getUnderlyingDecl());
+    if (Delete->isUsualDeallocationFunction())
+      Matches.push_back(F.getPair());
+  }
+
+  // There's exactly one suitable operator;  pick it.
+  if (Matches.size() == 1) {
+    Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl());
+    CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
+                          Matches[0]);
+    return false;
+
+  // We found multiple suitable operators;  complain about the ambiguity.
+  } else if (!Matches.empty()) {
+    Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
+      << Name << RD;
+
+    for (llvm::SmallVectorImpl<DeclAccessPair>::iterator
+           F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
+      Diag((*F)->getUnderlyingDecl()->getLocation(),
+           diag::note_member_declared_here) << Name;
+    return true;
   }
 
   // We did find operator delete/operator delete[] declarations, but
@@ -1316,10 +1332,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
       << Name << RD;
         
     for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
-         F != FEnd; ++F) {
-      Diag((*F)->getLocation(), diag::note_member_declared_here)
-        << Name;
-    }
+         F != FEnd; ++F)
+      Diag((*F)->getUnderlyingDecl()->getLocation(),
+           diag::note_member_declared_here) << Name;
 
     return true;
   }
diff --git a/test/CXX/special/class.dtor/p9.cpp b/test/CXX/special/class.dtor/p9.cpp
new file mode 100644 (file)
index 0000000..80acc24
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef typeof(sizeof(int)) size_t;
+
+// PR7803
+namespace test0 {
+  class A {
+  public:
+    static void operator delete(void *p) {};
+    virtual ~A();
+  };
+
+  class B : protected A {
+  public:
+    ~B();
+  };
+
+  class C : protected B {
+  public:
+    using B::operator delete;
+    ~C();
+  };
+
+  // Shouldn't have an error.
+  C::~C() {}
+}
+
+namespace test1 {
+  class A {
+  public:
+    static void operator delete(void *p) {}; // expected-note {{member 'operator delete' declared here}}
+    virtual ~A();
+  };
+
+  class B : protected A {
+  public:
+    static void operator delete(void *, size_t) {}; // expected-note {{member 'operator delete' declared here}}
+    ~B();
+  };
+
+  class C : protected B {
+  public:
+    using A::operator delete;
+    using B::operator delete;
+
+    ~C(); // expected-error {{multiple suitable 'operator delete' functions in 'C'}}
+  };
+}