CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
/// getDestructor - Returns the destructor decl for this class.
- const CXXDestructorDecl *getDestructor(ASTContext &Context);
+ CXXDestructorDecl *getDestructor(ASTContext &Context);
/// isLocalClass - If the class is a local class [class.local], returns
/// the enclosing function declaration.
return 0;
}
-const CXXDestructorDecl *
-CXXRecordDecl::getDestructor(ASTContext &Context) {
+CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName Name
llvm::tie(I, E) = lookup(Name);
assert(I != E && "Did not find a destructor!");
- const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
+ CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
assert(++I == E && "Found more than one destructor!");
return Dtor;
if (MD->isPure())
continue;
+ // Ignore implicit member functions, they are always marked as inline, but
+ // they don't have a body until they're defined.
+ if (MD->isImplicit())
+ continue;
+
const FunctionDecl *fn;
if (MD->getBody(fn) && !fn->isOutOfLine())
continue;
QualType Argument);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
- DeclarationName Name, FunctionDecl* &Operator,
- bool Diagnose=true);
+ DeclarationName Name, FunctionDecl* &Operator);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
/// as referenced.
void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
+ /// MaybeMarkVirtualImplicitMembersReferenced - If the passed in method is the
+ /// key function of the record decl, will mark virtual member functions as
+ /// referenced.
+ void MaybeMarkVirtualImplicitMembersReferenced(SourceLocation Loc,
+ CXXMethodDecl *MD);
+
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
void CheckConstructor(CXXConstructorDecl *Constructor);
QualType CheckDestructorDeclarator(Declarator &D,
FunctionDecl::StorageClass& SC);
- bool CheckDestructor(CXXDestructorDecl *Destructor, bool Diagnose=true);
+ bool CheckDestructor(CXXDestructorDecl *Destructor);
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
- // C++ [basic.def.odr]p2:
- // [...] A virtual member function is used if it is not pure. [...]
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) {
+ // C++ [basic.def.odr]p2:
+ // [...] A virtual member function is used if it is not pure. [...]
if (Method->isVirtual() && !Method->isPure())
MarkDeclarationReferenced(Method->getLocation(), Method);
+ MaybeMarkVirtualImplicitMembersReferenced(Method->getLocation(), Method);
+ }
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeOrdering.h"
ClassDecl->addDecl(Destructor);
AddOverriddenMethods(ClassDecl, Destructor);
- CheckDestructor(Destructor, false);
}
}
/// CheckDestructor - Checks a fully-formed destructor for well-formedness,
/// issuing any diagnostics required. Returns true on error.
-bool Sema::CheckDestructor(CXXDestructorDecl *Destructor, bool Diagnose) {
+bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
CXXRecordDecl *RD = Destructor->getParent();
if (Destructor->isVirtual()) {
FunctionDecl *OperatorDelete = 0;
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
- if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete, Diagnose))
+ if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
return true;
Destructor->setOperatorDelete(OperatorDelete);
} else {
Constructor->setUsed();
}
- return;
+
+ MaybeMarkVirtualImplicitMembersReferenced(CurrentLocation, Constructor);
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
VD->setDeclaredInCondition(true);
return Dcl;
}
+
+void Sema::MaybeMarkVirtualImplicitMembersReferenced(SourceLocation Loc,
+ CXXMethodDecl *MD) {
+ // Ignore dependent types.
+ if (MD->isDependentContext())
+ return;
+
+ CXXRecordDecl *RD = MD->getParent();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
+
+ if (!KeyFunction) {
+ // This record does not have a key function, so we assume that the vtable
+ // will be emitted when it's used by the constructor.
+ if (!isa<CXXConstructorDecl>(MD))
+ return;
+ } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
+ // We don't have the right key function.
+ return;
+ }
+
+ if (CXXDestructorDecl *Dtor = RD->getDestructor(Context)) {
+ if (Dtor->isImplicit() && Dtor->isVirtual())
+ MarkDeclarationReferenced(Loc, Dtor);
+ }
+
+ // FIXME: Need to handle the virtual assignment operator here too.
+}
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
- FunctionDecl* &Operator,
- bool Diagnose) {
+ FunctionDecl* &Operator) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
// We did find operator delete/operator delete[] declarations, but
// none of them were suitable.
if (!Found.empty()) {
- if (!Diagnose)
- return true;
Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
<< Name << RD;
--- /dev/null
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A {
+ virtual ~A();
+};
+
+struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
+ virtual void f();
+
+ void operator delete (void *, int); // expected-note {{'operator delete' declared here}}
+};
+
+void B::f() { // expected-note {{implicit default destructor for 'struct B' first required here}}
+}
+
+struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
+ C();
+ void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
+};
+
+C::C() { } // expected-note {{implicit default destructor for 'struct C' first required here}}
+
+struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
+ void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
+};
+
+void f() {
+ new D; // expected-note {{implicit default destructor for 'struct D' first required here}}
+}
+