From 8211effbd3abc5948a5d6924c87e72323016a376 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Tue, 24 Mar 2009 01:19:16 +0000 Subject: [PATCH] More work on diagnosing abstract classes. We can now handle cases like class C { void g(C c); virtual void f() = 0; }; In this case, C is not known to be abstract when doing semantic analysis on g. This is done by recursively traversing the abstract class and checking the types of member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67594 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclVisitor.h | 2 + lib/Sema/Sema.h | 12 +++++- lib/Sema/SemaDecl.cpp | 20 ++++++---- lib/Sema/SemaDeclCXX.cpp | 49 +++++++++++++++++++++++- lib/Sema/SemaExprCXX.cpp | 6 +-- lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +- test/SemaCXX/abstract.cpp | 14 ++++++- 7 files changed, 90 insertions(+), 15 deletions(-) diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h index 871b933172..28c10c7e18 100644 --- a/include/clang/AST/DeclVisitor.h +++ b/include/clang/AST/DeclVisitor.h @@ -13,6 +13,8 @@ #ifndef LLVM_CLANG_AST_DECLVISITOR_H #define LLVM_CLANG_AST_DECLVISITOR_H +#include "clang/AST/DeclTemplate.h" + namespace clang { #define DISPATCH(NAME, CLASS) \ diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ca5c299c02..4110fda673 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1638,8 +1638,16 @@ public: SourceLocation Loc, SourceRange Range); std::string getAmbiguousPathsDisplayString(BasePaths &Paths); - bool RequireNonAbstractType(SourceLocation Loc, QualType T, - unsigned DiagID, unsigned SelID); + enum AbstractDiagSelID { + AbstractNone = -1, + AbstractReturnType, + AbstractParamType, + AbstractVariableType, + AbstractFieldType + }; + + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, + AbstractDiagSelID SelID = AbstractNone); //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ccc3197446..a3b60047d6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1643,7 +1643,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // The variable can not have an abstract class type. if (RequireNonAbstractType(D.getIdentifierLoc(), R, diag::err_abstract_type_in_decl, - 2 /* variable type */)) + AbstractVariableType)) InvalidDecl = true; // The variable can not @@ -1815,11 +1815,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool isExplicit = D.getDeclSpec().isExplicitSpecified(); // Check that the return type is not an abstract class type. - if (RequireNonAbstractType(D.getIdentifierLoc(), + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!DC->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), R->getAsFunctionType()->getResultType(), diag::err_abstract_type_in_decl, - 0 /* return type */)) - InvalidDecl = true; + AbstractReturnType)) + InvalidDecl = true; bool isVirtualOkay = false; FunctionDecl *NewFD; @@ -2609,9 +2612,12 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { } // Parameters can not be abstract class types. - if (RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!CurContext->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, diag::err_abstract_type_in_decl, - 1 /* parameter type */)) + AbstractParamType)) D.setInvalidType(true); QualType T = adjustParameterType(parmDeclType); @@ -3544,7 +3550,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // Fields can not have abstract class types if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, - 3 /* field type */)) + AbstractFieldType)) InvalidDecl = true; // If this is declared as a bit-field, check the bit-field. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6f33c00526..d1b210df46 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -15,6 +15,7 @@ #include "SemaInherit.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Preprocessor.h" @@ -784,7 +785,7 @@ namespace { } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, - unsigned DiagID, unsigned SelID) { + unsigned DiagID, AbstractDiagSelID SelID) { if (!getLangOptions().CPlusPlus) return false; @@ -827,6 +828,49 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, return true; } +namespace { + class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser + : public DeclVisitor { + Sema &SemaRef; + CXXRecordDecl *AbstractClass; + + public: + AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac) + : SemaRef(SemaRef), AbstractClass(ac) {} + + bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { + bool Invalid = false; + + for (CXXRecordDecl::decl_iterator I = RD->decls_begin(), + E = RD->decls_end(); I != E; ++I) + Invalid |= Visit(*I); + + return Invalid; + } + + bool VisitCXXMethodDecl(const CXXMethodDecl *MD) { + // Check the return type. + QualType RTy = MD->getType()->getAsFunctionType()->getResultType(); + bool Invalid = + SemaRef.RequireNonAbstractType(MD->getLocation(), RTy, + diag::err_abstract_type_in_decl, + Sema::AbstractReturnType); + + for (CXXMethodDecl::param_const_iterator I = MD->param_begin(), + E = MD->param_end(); I != E; ++I) { + const ParmVarDecl *VD = *I; + Invalid |= + SemaRef.RequireNonAbstractType(VD->getLocation(), + VD->getOriginalType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType); + } + + return Invalid; + } + }; +} + void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclTy *TagDecl, SourceLocation LBrac, @@ -845,6 +889,9 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, RD->setAbstract(true); } + if (RD->isAbstract()) + AbstractClassUsageDiagnoser(*this, RD).Visit(RD); + if (!Template) AddImplicitlyDeclaredMembersToClass(RD); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 271f1da3ad..2abf87b23f 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -197,8 +197,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); - if (RequireNonAbstractType(TyBeginLoc, Ty, - diag::err_allocation_of_abstract_type, 0)) + if (RequireNonAbstractType(TyBeginLoc, Ty, + diag::err_allocation_of_abstract_type)) return ExprError(); exprs.release(); @@ -243,7 +243,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, return ExprError(); if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType, - diag::err_allocation_of_abstract_type, 0)) + diag::err_allocation_of_abstract_type)) return ExprError(); QualType ResultType = AllocType->isDependentType() diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b7a8f7a515..685b9cfd5b 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -357,7 +357,7 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), PInst->getType(), diag::err_abstract_type_in_decl, - 1 /* parameter type */)) + Sema::AbstractParamType)) PInst->setInvalidDecl(); Params.push_back(PInst); diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp index 08baacc49d..9c8e2dc977 100644 --- a/test/SemaCXX/abstract.cpp +++ b/test/SemaCXX/abstract.cpp @@ -51,4 +51,16 @@ void t5(void (*)(C)); // expected-error {{parameter type 'C' is an abstract clas typedef void (*Func)(C); // expected-error {{parameter type 'C' is an abstract class}} void t6(Func); - +class F { + F a() { } // expected-error {{return type 'F' is an abstract class}} + + class D { + void f(F c); // expected-error {{parameter type 'F' is an abstract class}} + }; + + union U { + void u(F c); // expected-error {{parameter type 'F' is an abstract class}} + }; + + virtual void f() = 0; // expected-note {{pure virtual function 'f'}} +}; -- 2.40.0