diff options
author | Anders Carlsson <andersca@mac.com> | 2009-03-24 01:19:16 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-03-24 01:19:16 +0000 |
commit | 8211effbd3abc5948a5d6924c87e72323016a376 (patch) | |
tree | e7a78360e3482db52dc96d9e4af335b59e24df4a /lib/Sema | |
parent | 42edd0d32a729d2735a6fb152ba6bf349bf0a169 (diff) |
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
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 |
5 files changed, 75 insertions, 14 deletions
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<AbstractClassUsageDiagnoser, bool> { + 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); |