]> granicus.if.org Git - clang/commitdiff
More work on diagnosing abstract classes. We can now handle cases like
authorAnders Carlsson <andersca@mac.com>
Tue, 24 Mar 2009 01:19:16 +0000 (01:19 +0000)
committerAnders Carlsson <andersca@mac.com>
Tue, 24 Mar 2009 01:19:16 +0000 (01:19 +0000)
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
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/abstract.cpp

index 871b933172caf046d941e1d0db2706d2f67b81d0..28c10c7e182f4b5f2211be63d320bf96e5e28b0c 100644 (file)
@@ -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) \
index ca5c299c024153ba4c90fe7455e3e0e7a3150aae..4110fda673fab496a04fdd86658416d456af1f7a 100644 (file)
@@ -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]
index ccc31974463e0a9b5e711a1f94ddf28e920d1f89..a3b60047d6261be33a1f0ea92752d0964e4f3080 100644 (file)
@@ -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.
index 6f33c005265199ef76423a76875065e9c3dd388c..d1b210df46291c5b7180119d70c6553a452f9514 100644 (file)
@@ -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);
 }
index 271f1da3adb3c8f86938b2eddc16a3f103958e6a..2abf87b23f5184fcddd6ebb8f449f1e578b4c5d5 100644 (file)
@@ -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()
index b7a8f7a515b2447c5005795dd9da42d223e817d5..685b9cfd5b91a0cd5ab4788f83bfb699edcbc150 100644 (file)
@@ -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);
index 08baacc49d6ee583863f24f29c5dc4b236520379..9c8e2dc977465fad71cd2ade5814b17ae687c1c5 100644 (file)
@@ -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'}}
+};