aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-08-04 00:31:26 +0000
committerJohn McCall <rjmccall@apple.com>2010-08-04 00:31:26 +0000
commit046a7466f23107bd752d9a8106aada85061699bc (patch)
tree3cd5ed25301ff833e57c48d569fe2fc87c6980cd
parent03b0df95cdef76fcdbad84bb10817733bd03220f (diff)
Look through using declarations when deciding whether to use an operator
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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaExprCXX.cpp37
-rw-r--r--test/CXX/special/class.dtor/p9.cpp48
3 files changed, 76 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ef59f985db..470261425a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 8b2fc7e56a..6d28dbdc12 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -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
index 0000000000..80acc2499d
--- /dev/null
+++ b/test/CXX/special/class.dtor/p9.cpp
@@ -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'}}
+ };
+}