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
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 6f33c00..d1b210d 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 @@
 }
 
 bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, 
-                                  unsigned DiagID, unsigned SelID) {
+                                  unsigned DiagID, AbstractDiagSelID SelID) {
   
   if (!getLangOptions().CPlusPlus)
     return false;
@@ -827,6 +828,49 @@
   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 @@
       RD->setAbstract(true);
   }
   
+  if (RD->isAbstract())
+    AbstractClassUsageDiagnoser(*this, RD).Visit(RD);
+    
   if (!Template)
     AddImplicitlyDeclaredMembersToClass(RD);
 }