aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp82
1 files changed, 81 insertions, 1 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 10e7bd4c97..b18b6c8f84 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -705,6 +705,77 @@ Sema::ActOnMemInitializer(DeclTy *ConstructorD,
return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs);
}
+namespace {
+ /// PureVirtualMethodCollector - traverses a class and its superclasses
+ /// and determines if it has any pure virtual methods.
+ class VISIBILITY_HIDDEN PureVirtualMethodCollector {
+ ASTContext &Context;
+
+ typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
+ MethodList Methods;
+
+ void Collect(const CXXRecordDecl* RD, MethodList& Methods);
+
+ public:
+ PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
+ : Context(Ctx) {
+
+ MethodList List;
+ Collect(RD, List);
+
+ // Copy the temporary list to methods, and make sure to ignore any
+ // null entries.
+ for (size_t i = 0, e = List.size(); i != e; ++i) {
+ if (List[i])
+ Methods.push_back(List[i]);
+ }
+ }
+
+ bool empty() const { return Methods.empty(); }
+ };
+
+ void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
+ MethodList& Methods) {
+ // First, collect the pure virtual methods for the base classes.
+ for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
+ BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
+ if (const RecordType *RT = Base->getType()->getAsRecordType()) {
+ const CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(RT->getDecl());
+ if (BaseDecl && BaseDecl->isAbstract())
+ Collect(BaseDecl, Methods);
+ }
+ }
+
+ // Next, zero out any pure virtual methods that this class overrides.
+ for (size_t i = 0, e = Methods.size(); i != e; ++i) {
+ const CXXMethodDecl *VMD = dyn_cast_or_null<CXXMethodDecl>(Methods[i]);
+ if (!VMD)
+ continue;
+
+ DeclContext::lookup_const_iterator I, E;
+ for (llvm::tie(I, E) = RD->lookup(VMD->getDeclName()); I != E; ++I) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I)) {
+ if (Context.getCanonicalType(MD->getType()) ==
+ Context.getCanonicalType(VMD->getType())) {
+ // We did find a matching method, which means that this is not a
+ // pure virtual method in the current class. Zero it out.
+ Methods[i] = 0;
+ }
+ }
+ }
+ }
+
+ // Finally, add pure virtual methods from this class.
+ for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
+ i != e; ++i) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
+ if (MD->isPure())
+ Methods.push_back(MD);
+ }
+ }
+ }
+}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclTy *TagDecl,
@@ -715,8 +786,17 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
(DeclTy**)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+ CXXRecordDecl *RD = cast<CXXRecordDecl>((Decl*)TagDecl);
+ if (!RD->isAbstract()) {
+ // Collect all the pure virtual methods and see if this is an abstract
+ // class after all.
+ PureVirtualMethodCollector Collector(Context, RD);
+ if (!Collector.empty())
+ RD->setAbstract(true);
+ }
+
if (!Template)
- AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl));
+ AddImplicitlyDeclaredMembersToClass(RD);
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared