From 046a7466f23107bd752d9a8106aada85061699bc Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 4 Aug 2010 00:31:26 +0000 Subject: [PATCH] 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 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 + lib/Sema/SemaExprCXX.cpp | 37 ++++++++++++----- test/CXX/special/class.dtor/p9.cpp | 48 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 test/CXX/special/class.dtor/p9.cpp 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 Matches; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { - if (CXXMethodDecl *Delete = dyn_cast(*F)) - if (Delete->isUsualDeallocationFunction()) { - Operator = Delete; - CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - F.getPair()); - return false; - } + CXXMethodDecl *Delete = cast((*F)->getUnderlyingDecl()); + if (Delete->isUsualDeallocationFunction()) + Matches.push_back(F.getPair()); + } + + // There's exactly one suitable operator; pick it. + if (Matches.size() == 1) { + Operator = cast(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::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'}} + }; +} -- 2.40.0