diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/Sema.h | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 46 |
3 files changed, 79 insertions, 3 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4082440f42..64cc088e96 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -151,6 +151,13 @@ public: /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. llvm::OwningPtr<CXXFieldCollector> FieldCollector; + typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy; + + /// PureVirtualClassDiagSet - a set of class declarations which we have + /// emitted a list of pure virtual functions. Used to prevent emitting the + /// same list more than once. + llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet; + /// \brief A mapping from external names to the most recent /// locally-scoped external declaration with that name. /// @@ -1627,6 +1634,8 @@ public: SourceLocation Loc, SourceRange Range); std::string getAmbiguousPathsDisplayString(BasePaths &Paths); + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned SelID); + //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] // diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7b45d5232f..255fd6c5ba 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1637,6 +1637,12 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else if (SC == VarDecl::None) SC = VarDecl::Static; } + + // The variable can not have an abstract class type. + if (RequireNonAbstractType(D.getIdentifierLoc(), R, 2 /* variable type */)) + InvalidDecl = true; + + // The variable can not NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), II, R, SC, // FIXME: Move to DeclGroup... @@ -1804,6 +1810,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + // Check that the return type is not an abstract class type. + if (RequireNonAbstractType(D.getIdentifierLoc(), + R->getAsFunctionType()->getResultType(), + 0 /* return type */)) + InvalidDecl = true; + bool isVirtualOkay = false; FunctionDecl *NewFD; if (D.getKind() == Declarator::DK_Constructor) { @@ -1977,8 +1989,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(Param->getLocation(), diag::ext_param_typedef_of_void); } } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) - Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param); + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + ParmVarDecl *PVD = (ParmVarDecl *)FTI.ArgInfo[i].Param; + + // Function parameters cannot have abstract class types. + if (RequireNonAbstractType(PVD->getLocation(), PVD->getType(), + 1 /* parameter type */)) + InvalidDecl = true; + Params.push_back(PVD); + } } NewFD->setParams(Context, &Params[0], Params.size()); @@ -3512,6 +3531,10 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } } + // Fields can not have abstract class types + if (RequireNonAbstractType(Loc, T, 3 /* field type */)) + InvalidDecl = true; + // If this is declared as a bit-field, check the bit-field. if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) { InvalidDecl = true; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b18b6c8f84..60d1692156 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -731,7 +731,10 @@ namespace { } } - bool empty() const { return Methods.empty(); } + bool empty() const { return Methods.empty(); } + + MethodList::const_iterator methods_begin() { return Methods.begin(); } + MethodList::const_iterator methods_end() { return Methods.end(); } }; void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD, @@ -777,6 +780,47 @@ namespace { } } +bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, + unsigned SelID) { + + if (!getLangOptions().CPlusPlus) + return false; + + const RecordType *RT = T->getAsRecordType(); + if (!RT) + return false; + + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + + if (!RD->isAbstract()) + return false; + + Diag(Loc, diag::err_abstract_type_in_decl) << SelID << RD->getDeclName(); + + // Check if we've already emitted the list of pure virtual functions for this + // class. + if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) + return true; + + PureVirtualMethodCollector Collector(Context, RD); + + for (PureVirtualMethodCollector::MethodList::const_iterator I = + Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + Diag(MD->getLocation(), diag::note_pure_virtual_function) << + MD->getDeclName(); + } + + if (!PureVirtualClassDiagSet) + PureVirtualClassDiagSet.reset(new RecordDeclSetTy); + PureVirtualClassDiagSet->insert(RD); + + return true; +} + void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclTy *TagDecl, SourceLocation LBrac, |