diff options
author | Anders Carlsson <andersca@mac.com> | 2009-11-15 22:49:34 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-11-15 22:49:34 +0000 |
commit | 6d7013940a37f03fd324ef438ff984a5369013b0 (patch) | |
tree | 4d2623e805b25334a720e7102b552e8e19b20754 | |
parent | 70f5bc77dbe4172bde860e15d8b3c29e0d5005cb (diff) |
Make sure that virtual destructors have delete operators.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@88877 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 8 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 26 |
4 files changed, 40 insertions, 6 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index eb3205f00f..6ede5dee1e 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1293,12 +1293,15 @@ private: uintptr_t *BaseOrMemberDestructions; unsigned NumBaseOrMemberDestructions; + FunctionDecl *OperatorDelete; + CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, bool isImplicitlyDeclared) : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*DInfo=*/0, false, isInline), ImplicitlyDefined(false), - BaseOrMemberDestructions(0), NumBaseOrMemberDestructions(0) { + BaseOrMemberDestructions(0), NumBaseOrMemberDestructions(0), + OperatorDelete(0) { setImplicit(isImplicitlyDeclared); } virtual void Destroy(ASTContext& C); @@ -1327,6 +1330,9 @@ public: ImplicitlyDefined = ID; } + void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; } + const FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + /// destr_iterator - Iterates through the member/base destruction list. /// destr_const_iterator - Iterates through the member/base destruction list. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0dd106ecaf..011747a1dc 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2346,6 +2346,7 @@ public: void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, FunctionDecl::StorageClass& SC); + void CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d3257c17a4..c6bbb9a438 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3105,9 +3105,13 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { CheckConstructor(Constructor); - } else if (isa<CXXDestructorDecl>(NewFD)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); + } else if (CXXDestructorDecl *Destructor = + dyn_cast<CXXDestructorDecl>(NewFD)) { + CXXRecordDecl *Record = Destructor->getParent(); QualType ClassType = Context.getTypeDeclType(Record); + + // FIXME: Shouldn't we be able to perform thisc heck even when the class + // type is dependent? Both gcc and edg can handle that. if (!ClassType->isDependentType()) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( @@ -3116,7 +3120,10 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, Diag(NewFD->getLocation(), diag::err_destructor_name); return NewFD->setInvalidDecl(); } + + CheckDestructor(Destructor); } + Record->setUserDeclaredDestructor(true); // C++ [class]p4: A POD-struct is an aggregate class that has [...] no // user-defined destructor. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a45c22e298..b0e18d865c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2368,6 +2368,28 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { ClassDecl->addedConstructor(Context, Constructor); } +/// CheckDestructor - Checks a fully-formed destructor for +/// well-formedness, issuing any diagnostics required. +void Sema::CheckDestructor(CXXDestructorDecl *Destructor) { + CXXRecordDecl *RD = Destructor->getParent(); + + if (Destructor->isVirtual()) { + SourceLocation Loc; + + if (!Destructor->isImplicit()) + Loc = Destructor->getLocation(); + else + Loc = RD->getLocation(); + + // If we have a virtual destructor, look up the deallocation function + FunctionDecl *OperatorDelete = 0; + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OO_Delete); + if (!FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) + Destructor->setOperatorDelete(OperatorDelete); + } +} + static inline bool FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && @@ -2997,9 +3019,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor) { assert((Destructor->isImplicit() && !Destructor->isUsed()) && "DefineImplicitDestructor - call it for implicit default dtor"); - - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(Destructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); // C++ [class.dtor] p5 // Before the implicitly-declared default destructor for a class is |