From: Anders Carlsson Date: Tue, 24 Mar 2009 17:23:42 +0000 (+0000) Subject: Fix the bug that Eli noticed where we wouldn't look at function decls outside the... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e65a3c8f181adc42786e0a409cd1e827f4ab37ff;p=clang Fix the bug that Eli noticed where we wouldn't look at function decls outside the class declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67627 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4110fda673..90ef136785 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1647,7 +1647,8 @@ public: }; bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, - AbstractDiagSelID SelID = AbstractNone); + AbstractDiagSelID SelID = AbstractNone, + const CXXRecordDecl *CurrentRD = 0); //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f21a462e66..af71e71ec8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -785,13 +785,15 @@ namespace { } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, - unsigned DiagID, AbstractDiagSelID SelID) { + unsigned DiagID, AbstractDiagSelID SelID, + const CXXRecordDecl *CurrentRD) { if (!getLangOptions().CPlusPlus) return false; if (const ArrayType *AT = Context.getAsArrayType(T)) - return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID); + return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID, + CurrentRD); if (const PointerType *PT = T->getAsPointerType()) { // Find the innermost pointer type. @@ -799,7 +801,8 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, PT = T; if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType())) - return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID); + return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID, + CurrentRD); } const RecordType *RT = T->getAsRecordType(); @@ -810,6 +813,9 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (!RD) return false; + if (CurrentRD && CurrentRD != RD) + return false; + if (!RD->isAbstract()) return false; @@ -843,40 +849,58 @@ namespace { Sema &SemaRef; CXXRecordDecl *AbstractClass; - public: - AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac) - : SemaRef(SemaRef), AbstractClass(ac) {} - - bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { + bool VisitDeclContext(const DeclContext *DC) { bool Invalid = false; - for (CXXRecordDecl::decl_iterator I = RD->decls_begin(), - E = RD->decls_end(); I != E; ++I) + for (CXXRecordDecl::decl_iterator I = DC->decls_begin(), + E = DC->decls_end(); I != E; ++I) Invalid |= Visit(*I); - + return Invalid; } - - bool VisitCXXMethodDecl(const CXXMethodDecl *MD) { + + public: + AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac) + : SemaRef(SemaRef), AbstractClass(ac) { + Visit(SemaRef.Context.getTranslationUnitDecl()); + } + + bool VisitFunctionDecl(const FunctionDecl *FD) { + if (FD->isThisDeclarationADefinition()) { + // No need to do the check if we're in a definition, because it requires + // that the return/param types are complete. + // because that requires + return VisitDeclContext(FD); + } + // Check the return type. - QualType RTy = MD->getType()->getAsFunctionType()->getResultType(); + QualType RTy = FD->getType()->getAsFunctionType()->getResultType(); bool Invalid = - SemaRef.RequireNonAbstractType(MD->getLocation(), RTy, + SemaRef.RequireNonAbstractType(FD->getLocation(), RTy, diag::err_abstract_type_in_decl, - Sema::AbstractReturnType); + Sema::AbstractReturnType, + AbstractClass); - for (CXXMethodDecl::param_const_iterator I = MD->param_begin(), - E = MD->param_end(); I != E; ++I) { + for (FunctionDecl::param_const_iterator I = FD->param_begin(), + E = FD->param_end(); I != E; ++I) { const ParmVarDecl *VD = *I; Invalid |= SemaRef.RequireNonAbstractType(VD->getLocation(), VD->getOriginalType(), diag::err_abstract_type_in_decl, - Sema::AbstractParamType); + Sema::AbstractParamType, + AbstractClass); } return Invalid; } + + bool VisitDecl(const Decl* D) { + if (const DeclContext *DC = dyn_cast(D)) + return VisitDeclContext(DC); + + return false; + } }; } @@ -898,8 +922,8 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, RD->setAbstract(true); } - if (RD->isAbstract()) - AbstractClassUsageDiagnoser(*this, RD).Visit(RD); + if (RD->isAbstract()) + AbstractClassUsageDiagnoser(*this, RD); if (!Template) AddImplicitlyDeclaredMembersToClass(RD); diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp index 0230588139..20b35da83d 100644 --- a/test/SemaCXX/abstract.cpp +++ b/test/SemaCXX/abstract.cpp @@ -66,3 +66,19 @@ class F { virtual void f() = 0; // expected-note {{pure virtual function 'f'}} }; + +class Abstract; + +void t7(Abstract a); // expected-error {{parameter type 'Abstract' is an abstract class}} + +void t8() { + void h(Abstract a); // expected-error {{parameter type 'Abstract' is an abstract class}} +} + +namespace N { + void h(Abstract a); // expected-error {{parameter type 'Abstract' is an abstract class}} +} + +class Abstract { + virtual void f() = 0; // expected-note {{pure virtual function 'f'}} +};