Sema-check virtual declarations. Complete dynamic_cast checking.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58804 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 2065677..7be7197 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -219,6 +219,10 @@
   /// Aggregate - True when this class is an aggregate.
   bool Aggregate : 1;
 
+  /// Polymorphic - True when this class is polymorphic, i.e. has at least one
+  /// virtual member or derives from a polymorphic class.
+  bool Polymorphic : 1;
+
   /// Bases - Base classes of this class.
   /// FIXME: This is wasted space for a union.
   CXXBaseSpecifier *Bases;
@@ -238,8 +242,8 @@
                 SourceLocation L, IdentifierInfo *Id) 
     : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
       UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
-      Aggregate(true), Bases(0), NumBases(0), Constructors(DC, Id),
-      Destructor(0) { }
+      Aggregate(true), Polymorphic(false), Bases(0), NumBases(0),
+      Constructors(DC, Id), Destructor(0) { }
 
   ~CXXRecordDecl();
 
@@ -327,6 +331,14 @@
   /// [dcl.init.aggr]).
   void setAggregate(bool Agg) { Aggregate = Agg; }
 
+  /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
+  /// which means that the class contains or inherits a virtual function.
+  bool isPolymorphic() const { return Polymorphic; }
+
+  /// setPolymorphic - Set whether this class is polymorphic (C++
+  /// [class.virtual]).
+  void setPolymorphic(bool Poly) { Polymorphic = Poly; }
+
   /// viewInheritance - Renders and displays an inheritance diagram
   /// for this C++ class and all of its base classes (transitively) using
   /// GraphViz.
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 1972716..fedee73 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -667,6 +667,8 @@
 // C++ class members
 DIAG(err_storageclass_invalid_for_member, ERROR,
      "storage class specified for a member declaration")
+DIAG(err_virtual_non_function, ERROR,
+     "'virtual' can only appear on non-static member functions")
 DIAG(err_not_bitfield_type, ERROR,
      "cannot declare '%0' to be a bit-field type")
 DIAG(err_static_not_bitfield, ERROR,
@@ -1142,6 +1144,8 @@
      "'%0' is incomplete")
 DIAG(err_bad_dynamic_cast_not_ptr, ERROR,
      "'%0' is not a pointer")
+DIAG(err_bad_dynamic_cast_not_polymorphic, ERROR,
+     "'%0' is not polymorphic")
 
 DIAG(err_invalid_use_of_function_type, ERROR,
      "a function type is not allowed here")
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ea3c175..bdc2faf 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -310,6 +310,15 @@
     return true;
   }
 
+  // If the base class is polymorphic, the new one is, too.
+  RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
+  assert(BaseDecl && "Record type has no declaration");
+  BaseDecl = BaseDecl->getDefinition(Context);
+  assert(BaseDecl && "Base type is not incomplete, but has no definition");
+  if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic()) {
+    cast<CXXRecordDecl>(Decl)->setPolymorphic(true);
+  }
+
   // Create the base specifier.
   return new CXXBaseSpecifier(SpecifierRange, Virtual, 
                               BaseType->isClassType(), Access, BaseType);
@@ -468,8 +477,16 @@
   if (isInstField && (AS == AS_private || AS == AS_protected))
     cast<CXXRecordDecl>(CurContext)->setAggregate(false);
 
-  // FIXME: If the member is a virtual function, mark it its class as
-  // a non-aggregate.
+  if (DS.isVirtualSpecified()) {
+    if (!isFunc || DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+      Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function);
+      InvalidDecl = true;
+    } else {
+      CXXRecordDecl *CurClass = cast<CXXRecordDecl>(CurContext);
+      CurClass->setAggregate(false);
+      CurClass->setPolymorphic(true);
+    }
+  }
 
   if (BitWidth) {
     // C++ 9.6p2: Only when declaring an unnamed bit-field may the
diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp
index 980e012..bf559d6 100644
--- a/lib/Sema/SemaNamedCast.cpp
+++ b/lib/Sema/SemaNamedCast.cpp
@@ -671,7 +671,12 @@
   }
 
   // C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
-  // FIXME: Information not yet available.
+  const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Context);
+  assert(SrcDecl && "Definition missing");
+  if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
+    Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic,
+      SrcPointee.getUnqualifiedType().getAsString(), SrcExpr->getSourceRange());
+  }
 
   // Done. Everything else is run-time checks.
 }
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 855bc27..75b872f 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -17,10 +17,12 @@
   int m;
 };
 
-// FIXME: virtual functions
 struct NonAggr4 {
+  int m;
+  virtual void f();
 };
 
 NonAggr1 na1 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr1' with an initializer list}}
 NonAggr2 na2 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr2' with an initializer list}}
 NonAggr3 na3 = { 17 }; // expected-error{{initialization of non-aggregate type 'class NonAggr3' with an initializer list}}
+NonAggr4 na4 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr4' with an initializer list}}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index c3886f3..7eeecdc 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -47,12 +47,16 @@
   }
 
   int f1(int p) {
-   A z = 6;
-   return p + x + this->y + z;
+    A z = 6;
+    return p + x + this->y + z;
   }
 
   typedef int A;
 
+  virtual int vi; // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+  virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+  virtual int vif();
+
 private:
   int x,y;
   static int sx;
diff --git a/test/SemaCXX/dynamic-cast.cpp b/test/SemaCXX/dynamic-cast.cpp
index 0a4dbc2..5e47b9a 100644
--- a/test/SemaCXX/dynamic-cast.cpp
+++ b/test/SemaCXX/dynamic-cast.cpp
@@ -10,6 +10,15 @@
 
 struct Incomplete;
 
+struct Poly
+{
+  virtual void f();
+};
+
+struct PolyDerived : Poly
+{
+};
+
 void basic_bad()
 {
   // ptr -> nonptr
@@ -52,4 +61,14 @@
   (void)dynamic_cast<A&>(*((F*)0)); // expected-error {{ambiguous conversion from derived class 'struct F' to base class 'struct A':\n    struct F -> struct B -> struct A\n    struct F -> struct E -> struct A}}
 }
 
-// FIXME: Other test cases require recognition of polymorphic classes.
+void poly()
+{
+  (void)dynamic_cast<A*>((Poly*)0);
+  (void)dynamic_cast<A&>(*((Poly*)0));
+  (void)dynamic_cast<A*>((PolyDerived*)0);
+  (void)dynamic_cast<A&>(*((PolyDerived*)0));
+
+  // Not polymorphic source
+  (void)dynamic_cast<Poly*>((A*)0); // expected-error {{'struct A' is not polymorphic}}
+  (void)dynamic_cast<PolyDerived&>(*((A*)0)); // expected-error {{'struct A' is not polymorphic}}
+}