[cfe-commits] r99351 - in /cfe/trunk: include/clang/AST/CXXInheritance.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/CXXInheritance.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/class.derived/class.abstract/p4.cpp test/CXX/class.derived/class.abstract/p5.cpp test/CXX/class.derived/class.virtual/p2.cpp

Douglas Gregor dgregor at apple.com
Tue Mar 23 16:47:56 PDT 2010


Author: dgregor
Date: Tue Mar 23 18:47:56 2010
New Revision: 99351

URL: http://llvm.org/viewvc/llvm-project?rev=99351&view=rev
Log:
Implement computation of the final overriders for each virtual
function within a class hierarchy (C++ [class.virtual]p2).

We use the final-overrider computation to determine when a particular
class is ill-formed because it has multiple final overriders for a
given virtual function (e.g., because two virtual functions override
the same virtual function in the same virtual base class). Fixes
PR5973.

We also use the final-overrider computation to determine which virtual
member functions are pure when determining whether a class is
abstract or diagnosing the improper use of an abstract class. The
prior approach to determining whether there were any pure virtual
functions in a class didn't cope with virtual base class subobjects
properly, and could not easily be fixed to deal with the oddities of
subobject hiding. Fixes PR6631.


Added:
    cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp   (with props)
    cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp   (with props)
    cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/CXXInheritance.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/CXXInheritance.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=99351&r1=99350&r2=99351&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
+++ cfe/trunk/include/clang/AST/CXXInheritance.h Tue Mar 23 18:47:56 2010
@@ -19,6 +19,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include <list>
 #include <map>
@@ -227,6 +228,137 @@
   /// object.
   void swap(CXXBasePaths &Other);
 };
+
+/// \brief Uniquely identifies a virtual method within a class
+/// hierarchy by the method itself and a class subobject number.
+struct UniqueVirtualMethod {
+  UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { }
+
+  UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
+                      const CXXRecordDecl *InVirtualSubobject)
+    : Method(Method), Subobject(Subobject), 
+      InVirtualSubobject(InVirtualSubobject) { }
+
+  /// \brief The overriding virtual method.
+  CXXMethodDecl *Method;
+
+  /// \brief The subobject in which the overriding virtual method
+  /// resides.
+  unsigned Subobject;
+
+  /// \brief The virtual base class subobject of which this overridden
+  /// virtual method is a part. Note that this records the closest
+  /// derived virtual base class subobject.
+  const CXXRecordDecl *InVirtualSubobject;
+
+  friend bool operator==(const UniqueVirtualMethod &X,
+                         const UniqueVirtualMethod &Y) {
+    return X.Method == Y.Method && X.Subobject == Y.Subobject &&
+      X.InVirtualSubobject == Y.InVirtualSubobject;
+  }
+
+  friend bool operator!=(const UniqueVirtualMethod &X,
+                         const UniqueVirtualMethod &Y) {
+    return !(X == Y);
+  }
+};
+
+/// \brief The set of methods that override a given virtual method in
+/// each subobject where it occurs.
+///
+/// The first part of the pair is the subobject in which the
+/// overridden virtual function occurs, while the second part of the
+/// pair is the virtual method that overrides it (including the
+/// subobject in which that virtual function occurs).
+class OverridingMethods {
+  llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> > 
+    Overrides;
+
+public:
+  // Iterate over the set of subobjects that have overriding methods.
+  typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+            ::iterator iterator;
+  typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+            ::const_iterator const_iterator;
+  iterator begin() { return Overrides.begin(); }
+  const_iterator begin() const { return Overrides.begin(); }
+  iterator end() { return Overrides.end(); }
+  const_iterator end() const { return Overrides.end(); }
+  unsigned size() const { return Overrides.size(); }
+
+  // Iterate over the set of overriding virtual methods in a given
+  // subobject.
+  typedef llvm::SmallVector<UniqueVirtualMethod, 4>::iterator 
+    overriding_iterator;
+  typedef llvm::SmallVector<UniqueVirtualMethod, 4>::const_iterator
+    overriding_const_iterator;
+
+  // Add a new overriding method for a particular subobject.
+  void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding);
+
+  // Add all of the overriding methods from "other" into overrides for
+  // this method. Used when merging the overrides from multiple base
+  // class subobjects.
+  void add(const OverridingMethods &Other);
+
+  // Replace all overriding virtual methods in all subobjects with the
+  // given virtual method.
+  void replaceAll(UniqueVirtualMethod Overriding);
+};
+
+/// \brief A mapping from each virtual member function to its set of
+/// final overriders.
+///
+/// Within a class hierarchy for a given derived class, each virtual
+/// member function in that hierarchy has one or more "final
+/// overriders" (C++ [class.virtual]p2). A final overrider for a
+/// virtual function "f" is the virtual function that will actually be
+/// invoked when dispatching a call to "f" through the
+/// vtable. Well-formed classes have a single final overrider for each
+/// virtual function; in abstract classes, the final overrider for at
+/// least one virtual function is a pure virtual function. Due to
+/// multiple, virtual inheritance, it is possible for a class to have
+/// more than one final overrider. Athough this is an error (per C++
+/// [class.virtual]p2), it is not considered an error here: the final
+/// overrider map can represent multiple final overriders for a
+/// method, and it is up to the client to determine whether they are
+/// problem. For example, the following class \c D has two final
+/// overriders for the virtual function \c A::f(), one in \c C and one
+/// in \c D:
+///
+/// \code
+///   struct A { virtual void f(); };
+///   struct B : virtual A { virtual void f(); };
+///   struct C : virtual A { virtual void f(); };
+///   struct D : B, C { };
+/// \endcode
+///
+/// This data structure contaings a mapping from every virtual
+/// function *that does not override an existing virtual function* and
+/// in every subobject where that virtual function occurs to the set
+/// of virtual functions that override it. Thus, the same virtual
+/// function \c A::f can actually occur in multiple subobjects of type
+/// \c A due to multiple inheritance, and may be overriden by
+/// different virtual functions in each, as in the following example:
+///
+/// \code
+///   struct A { virtual void f(); };
+///   struct B : A { virtual void f(); };
+///   struct C : A { virtual void f(); };
+///   struct D : B, C { };
+/// \endcode
+///
+/// Unlike in the previous example, where the virtual functions \c
+/// B::f and \c C::f both overrode \c A::f in the same subobject of
+/// type \c A, in this example the two virtual functions both override
+/// \c A::f but in *different* subobjects of type A. This is
+/// represented by numbering the subobjects in which the overridden
+/// and the overriding virtual member functions are located. Subobject
+/// 0 represents the virtua base class subobject of that type, while
+/// subobject numbers greater than 0 refer to non-virtual base class
+/// subobjects of that type.
+class CXXFinalOverriderMap 
+  : public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
   
 } // end namespace clang
 

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=99351&r1=99350&r2=99351&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Mar 23 18:47:56 2010
@@ -33,6 +33,7 @@
 class CXXMethodDecl;
 class CXXRecordDecl;
 class CXXMemberLookupCriteria;
+class CXXFinalOverriderMap;
 class FriendDecl;
   
 /// \brief Represents any kind of function declaration, whether it is a
@@ -879,7 +880,12 @@
   static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
                                             CXXBasePath &Path,
                                             void *UserData);
-  
+
+  /// \brief Retrieve the final overriders for each virtual member
+  /// function in the class hierarchy where this class is the
+  /// most-derived class in the class hierarchy.
+  void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const;
+
   /// viewInheritance - Renders and displays an inheritance diagram
   /// for this C++ class and all of its base classes (transitively) using
   /// GraphViz.

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=99351&r1=99350&r2=99351&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Mar 23 18:47:56 2010
@@ -391,7 +391,11 @@
   "%select{return|parameter|variable|field}0 type %1 is an abstract class">;
 def err_allocation_of_abstract_type : Error<
   "allocation of an object of abstract type %0">;
-  
+
+def err_multiple_final_overriders : Error<
+  "virtual function %q0 has more than one final overrider in %1">; 
+def note_final_overrider : Note<"final overrider of %q0 in %1">;
+
 def err_type_defined_in_type_specifier : Error<
   "%0 can not be defined in a type specifier">;
 def err_type_defined_in_result_type : Error<

Modified: cfe/trunk/lib/AST/CXXInheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CXXInheritance.cpp?rev=99351&r1=99350&r2=99351&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CXXInheritance.cpp (original)
+++ cfe/trunk/lib/AST/CXXInheritance.cpp Tue Mar 23 18:47:56 2010
@@ -416,3 +416,240 @@
   
   return false;
 }
+
+void OverridingMethods::add(unsigned OverriddenSubobject, 
+                            UniqueVirtualMethod Overriding) {
+  llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+    = Overrides[OverriddenSubobject];
+  if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), 
+                Overriding) == SubobjectOverrides.end())
+    SubobjectOverrides.push_back(Overriding);
+}
+
+void OverridingMethods::add(const OverridingMethods &Other) {
+  for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) {
+    for (overriding_const_iterator M = I->second.begin(), 
+                                MEnd = I->second.end();
+         M != MEnd; 
+         ++M)
+      add(I->first, *M);
+  }
+}
+
+void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) {
+  for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) {
+    I->second.clear();
+    I->second.push_back(Overriding);
+  }
+}
+
+
+namespace {
+  class FinalOverriderCollector {
+    /// \brief The number of subobjects of a given class type that
+    /// occur within the class hierarchy.
+    llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;
+
+    /// \brief Overriders for each virtual base subobject.
+    llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;
+
+    CXXFinalOverriderMap FinalOverriders;
+
+  public:
+    ~FinalOverriderCollector();
+
+    void Collect(const CXXRecordDecl *RD, bool VirtualBase,
+                 const CXXRecordDecl *InVirtualSubobject,
+                 CXXFinalOverriderMap &Overriders);
+  };
+}
+
+void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, 
+                                      bool VirtualBase,
+                                      const CXXRecordDecl *InVirtualSubobject,
+                                      CXXFinalOverriderMap &Overriders) {
+  unsigned SubobjectNumber = 0;
+  if (!VirtualBase)
+    SubobjectNumber
+      = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];
+
+  for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
+         BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
+    if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
+      const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
+      if (!BaseDecl->isPolymorphic())
+        continue;
+
+      if (Overriders.empty() && !Base->isVirtual()) {
+        // There are no other overriders of virtual member functions,
+        // so let the base class fill in our overriders for us.
+        Collect(BaseDecl, false, InVirtualSubobject, Overriders);
+        continue;
+      }
+
+      // Collect all of the overridders from the base class subobject
+      // and merge them into the set of overridders for this class.
+      // For virtual base classes, populate or use the cached virtual
+      // overrides so that we do not walk the virtual base class (and
+      // its base classes) more than once.
+      CXXFinalOverriderMap ComputedBaseOverriders;
+      CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;
+      if (Base->isVirtual()) {
+        CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];
+        if (!MyVirtualOverriders) {
+          MyVirtualOverriders = new CXXFinalOverriderMap;
+          Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders);
+        }
+
+        BaseOverriders = MyVirtualOverriders;
+      } else
+        Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders);
+
+      // Merge the overriders from this base class into our own set of
+      // overriders.
+      for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(), 
+                               OMEnd = BaseOverriders->end();
+           OM != OMEnd;
+           ++OM) {
+        const CXXMethodDecl *CanonOM
+          = cast<CXXMethodDecl>(OM->first->getCanonicalDecl());
+        Overriders[CanonOM].add(OM->second);
+      }
+    }
+  }
+
+  for (CXXRecordDecl::method_iterator M = RD->method_begin(), 
+                                   MEnd = RD->method_end();
+       M != MEnd;
+       ++M) {
+    // We only care about virtual methods.
+    if (!M->isVirtual())
+      continue;
+
+    CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl());
+
+    if (CanonM->begin_overridden_methods()
+                                       == CanonM->end_overridden_methods()) {
+      // This is a new virtual function that does not override any
+      // other virtual function. Add it to the map of virtual
+      // functions for which we are tracking overridders. 
+
+      // C++ [class.virtual]p2:
+      //   For convenience we say that any virtual function overrides itself.
+      Overriders[CanonM].add(SubobjectNumber,
+                             UniqueVirtualMethod(CanonM, SubobjectNumber,
+                                                 InVirtualSubobject));
+      continue;
+    }
+
+    // This virtual method overrides other virtual methods, so it does
+    // not add any new slots into the set of overriders. Instead, we
+    // replace entries in the set of overriders with the new
+    // overrider. To do so, we dig down to the original virtual
+    // functions using data recursion and update all of the methods it
+    // overrides.
+    typedef std::pair<CXXMethodDecl::method_iterator, 
+                      CXXMethodDecl::method_iterator> OverriddenMethods;
+    llvm::SmallVector<OverriddenMethods, 4> Stack;
+    Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(),
+                                   CanonM->end_overridden_methods()));
+    while (!Stack.empty()) {
+      OverriddenMethods OverMethods = Stack.back();
+      Stack.pop_back();
+
+      for (; OverMethods.first != OverMethods.second; ++OverMethods.first) {
+        const CXXMethodDecl *CanonOM
+          = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl());
+        if (CanonOM->begin_overridden_methods()
+                                       == CanonOM->end_overridden_methods()) {
+          // C++ [class.virtual]p2:
+          //   A virtual member function C::vf of a class object S is
+          //   a final overrider unless the most derived class (1.8)
+          //   of which S is a base class subobject (if any) declares
+          //   or inherits another member function that overrides vf.
+          //
+          // Treating this object like the most derived class, we
+          // replace any overrides from base classes with this
+          // overriding virtual function.
+          Overriders[CanonOM].replaceAll(
+                                 UniqueVirtualMethod(CanonM, SubobjectNumber,
+                                                     InVirtualSubobject));
+          continue;
+        } 
+
+        // Continue recursion to the methods that this virtual method
+        // overrides.
+        Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(),
+                                       CanonOM->end_overridden_methods()));
+      }
+    }
+  }
+}
+
+FinalOverriderCollector::~FinalOverriderCollector() {
+  for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator
+         VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();
+       VO != VOEnd; 
+       ++VO)
+    delete VO->second;
+}
+
+void 
+CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
+  FinalOverriderCollector Collector;
+  Collector.Collect(this, false, 0, FinalOverriders);
+
+  // Weed out any final overriders that come from virtual base class
+  // subobjects that were hidden by other subobjects along any path.
+  // This is the final-overrider variant of C++ [class.member.lookup]p10.
+  for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(), 
+                           OMEnd = FinalOverriders.end();
+       OM != OMEnd;
+       ++OM) {
+    for (OverridingMethods::iterator SO = OM->second.begin(), 
+                                  SOEnd = OM->second.end();
+         SO != SOEnd; 
+         ++SO) {
+      llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+      if (Overriding.size() < 2)
+        continue;
+
+      for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator 
+             Pos = Overriding.begin(), PosEnd = Overriding.end();
+           Pos != PosEnd;
+           /* increment in loop */) {
+        if (!Pos->InVirtualSubobject) {
+          ++Pos;
+          continue;
+        }
+
+        // We have an overriding method in a virtual base class
+        // subobject (or non-virtual base class subobject thereof);
+        // determine whether there exists an other overriding method
+        // in a base class subobject that hides the virtual base class
+        // subobject.
+        bool Hidden = false;
+        for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+               OP = Overriding.begin(), OPEnd = Overriding.end();
+             OP != OPEnd && !Hidden; 
+             ++OP) {
+          if (Pos == OP)
+            continue;
+
+          if (OP->Method->getParent()->isVirtuallyDerivedFrom(
+                         const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject)))
+            Hidden = true;
+        }
+
+        if (Hidden) {
+          // The current overriding function is hidden by another
+          // overriding function; remove this one.
+          Pos = Overriding.erase(Pos);
+          PosEnd = Overriding.end();
+        } else {
+          ++Pos;
+        }
+      }
+    }
+  }
+}

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=99351&r1=99350&r2=99351&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Mar 23 18:47:56 2010
@@ -1932,87 +1932,6 @@
     SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
 }
 
-namespace {
-  /// PureVirtualMethodCollector - traverses a class and its superclasses
-  /// and determines if it has any pure virtual methods.
-  class PureVirtualMethodCollector {
-    ASTContext &Context;
-
-  public:
-    typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
-
-  private:
-    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(); }
-
-    MethodList::const_iterator methods_begin() { return Methods.begin(); }
-    MethodList::const_iterator methods_end() { return Methods.end(); }
-  };
-
-  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()->getAs<RecordType>()) {
-        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.
-    typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy;
-
-    MethodSetTy OverriddenMethods;
-    size_t MethodsSize = Methods.size();
-
-    for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
-         i != e; ++i) {
-      // Traverse the record, looking for methods.
-      if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
-        // If the method is pure virtual, add it to the methods vector.
-        if (MD->isPure())
-          Methods.push_back(MD);
-
-        // Record all the overridden methods in our set.
-        for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
-             E = MD->end_overridden_methods(); I != E; ++I) {
-          // Keep track of the overridden methods.
-          OverriddenMethods.insert(*I);
-        }
-      }
-    }
-
-    // Now go through the methods and zero out all the ones we know are
-    // overridden.
-    for (size_t i = 0, e = MethodsSize; i != e; ++i) {
-      if (OverriddenMethods.count(Methods[i]))
-        Methods[i] = 0;
-    }
-
-  }
-}
-
-
 bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
                                   unsigned DiagID, AbstractDiagSelID SelID,
                                   const CXXRecordDecl *CurrentRD) {
@@ -2066,14 +1985,32 @@
   if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
     return true;
 
-  PureVirtualMethodCollector Collector(Context, RD);
+  CXXFinalOverriderMap FinalOverriders;
+  RD->getFinalOverriders(FinalOverriders);
 
-  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();
+  for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), 
+                                   MEnd = FinalOverriders.end();
+       M != MEnd; 
+       ++M) {
+    for (OverridingMethods::iterator SO = M->second.begin(), 
+                                  SOEnd = M->second.end();
+         SO != SOEnd; ++SO) {
+      // C++ [class.abstract]p4:
+      //   A class is abstract if it contains or inherits at least one
+      //   pure virtual function for which the final overrider is pure
+      //   virtual.
+
+      // 
+      if (SO->second.size() != 1)
+        continue;
+
+      if (!SO->second.front().Method->isPure())
+        continue;
+
+      Diag(SO->second.front().Method->getLocation(), 
+           diag::note_pure_virtual_function) 
+        << SO->second.front().Method->getDeclName();
+    }
   }
 
   if (!PureVirtualClassDiagSet)
@@ -2162,15 +2099,71 @@
   for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I)
     Convs->setAccess(I, (*I)->getAccess());
 
-  if (!Record->isAbstract()) {
-    // Collect all the pure virtual methods and see if this is an abstract
-    // class after all.
-    PureVirtualMethodCollector Collector(Context, Record);
-    if (!Collector.empty())
-      Record->setAbstract(true);
+  // Determine whether we need to check for final overriders. We do
+  // this either when there are virtual base classes (in which case we
+  // may end up finding multiple final overriders for a given virtual
+  // function) or any of the base classes is abstract (in which case
+  // we might detect that this class is abstract).
+  bool CheckFinalOverriders = false;
+  if (Record->isPolymorphic() && !Record->isInvalidDecl() &&
+      !Record->isDependentType()) {
+    if (Record->getNumVBases())
+      CheckFinalOverriders = true;
+    else if (!Record->isAbstract()) {
+      for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(),
+                                                 BEnd = Record->bases_end();
+           B != BEnd; ++B) {
+        CXXRecordDecl *BaseDecl 
+          = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
+        if (BaseDecl->isAbstract()) {
+          CheckFinalOverriders = true; 
+          break;
+        }
+      }
+    }
+  }
+
+  if (CheckFinalOverriders) {
+    CXXFinalOverriderMap FinalOverriders;
+    Record->getFinalOverriders(FinalOverriders);
+
+    for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), 
+                                     MEnd = FinalOverriders.end();
+         M != MEnd; ++M) {
+      for (OverridingMethods::iterator SO = M->second.begin(), 
+                                    SOEnd = M->second.end();
+           SO != SOEnd; ++SO) {
+        assert(SO->second.size() > 0 && 
+               "All virtual functions have overridding virtual functions");
+        if (SO->second.size() == 1) {
+          // C++ [class.abstract]p4:
+          //   A class is abstract if it contains or inherits at least one
+          //   pure virtual function for which the final overrider is pure
+          //   virtual.
+          if (SO->second.front().Method->isPure())
+            Record->setAbstract(true);
+          continue;
+        }
+
+        // C++ [class.virtual]p2:
+        //   In a derived class, if a virtual member function of a base
+        //   class subobject has more than one final overrider the
+        //   program is ill-formed.
+        Diag(Record->getLocation(), diag::err_multiple_final_overriders)
+          << (NamedDecl *)M->first << Record;
+        Diag(M->first->getLocation(), diag::note_overridden_virtual_function);
+        for (OverridingMethods::overriding_iterator OM = SO->second.begin(), 
+                                                 OMEnd = SO->second.end();
+             OM != OMEnd; ++OM)
+          Diag(OM->Method->getLocation(), diag::note_final_overrider)
+            << (NamedDecl *)M->first << OM->Method->getParent();
+        
+        Record->setInvalidDecl();
+      }
+    }
   }
 
-  if (Record->isAbstract())
+  if (Record->isAbstract() && !Record->isInvalidDecl())
     (void)AbstractClassUsageDiagnoser(*this, Record);
 }
 

Added: cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp?rev=99351&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp (added)
+++ cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp Tue Mar 23 18:47:56 2010
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR6631 {
+  struct A { 
+    virtual void f() = 0;
+  };
+
+  struct B : virtual A { };
+
+  struct C : virtual A { 
+    virtual void f();
+  };
+
+  struct D : public B, public C { 
+    virtual void f();
+  };
+
+  void f() {
+    (void)new D; // okay
+  }
+}
+
+// Check cases where we have a virtual function that is pure in one
+// subobject but not pure in another subobject.
+namespace PartlyPure {
+  struct A { 
+    virtual void f() = 0; // expected-note{{pure virtual function}}
+  };
+
+  struct B : A {
+    virtual void f();
+  };
+
+  struct C : virtual A { };
+
+  struct D : B, C { };
+
+  void f() {
+    (void) new D; // expected-error{{abstract type}}
+  }
+}
+
+namespace NonPureAlongOnePath {
+  struct A { 
+    virtual void f() = 0;
+  };
+
+  struct B : virtual A {
+    virtual void f();
+  };
+
+  struct C : virtual A { };
+
+  struct D : B, C { };
+
+  void f() {
+    (void) new D; // okay
+  }  
+}
+
+namespace NonPureAlongOnePath2 {
+  struct Aprime { 
+    virtual void f() = 0;
+  };
+
+  struct A : Aprime {
+  };
+
+  struct B : virtual A {
+    virtual void f();
+  };
+
+  struct C : virtual A { };
+
+  struct D : B, C { };
+
+  void f() {
+    (void) new D; // okay
+  }  
+}

Propchange: cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/class.derived/class.abstract/p4.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp?rev=99351&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp (added)
+++ cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp Tue Mar 23 18:47:56 2010
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+  virtual void f() = 0; // expected-note{{pure virtual function}}
+};
+
+struct B : A {
+  virtual void f();
+};
+
+struct C : B {
+  virtual void f() = 0; // expected-note 2{{pure virtual function}}
+};
+
+struct D : C {
+};
+
+void test() {
+  (void)new A; // expected-error{{object of abstract type}}
+  (void)new B;
+  (void)new C; // expected-error{{object of abstract type}}
+  (void)new D; // expected-error{{object of abstract type}}
+}

Propchange: cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/class.derived/class.abstract/p5.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp?rev=99351&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp (added)
+++ cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp Tue Mar 23 18:47:56 2010
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct A {
+  virtual void f() = 0; // expected-note 2{{overridden virtual function}}
+};
+
+struct Aprime : virtual A {
+  virtual void f();
+};
+
+struct B : Aprime {
+  virtual void f(); // expected-note 3{{final overrider of 'A::f'}}
+};
+
+struct C : virtual A {
+  virtual void f(); // expected-note{{final overrider of 'A::f'}}
+};
+
+struct D : B, C { }; // expected-error{{virtual function 'A::f' has more than one final overrider in 'D'}}
+
+struct B2 : B { };
+
+struct E : B, B2 { }; //expected-error{{virtual function 'A::f' has more than one final overrider in 'E'}}
+
+struct F : B, B2 {
+  virtual void f(); // okay
+};
+
+struct G : F { }; // okay
+
+struct H : G, A { }; // okay
+
+namespace MultipleSubobjects {
+  struct A { virtual void f(); };
+  struct B : A { virtual void f(); };
+  struct C : A { virtual void f(); };
+  struct D : B, C { }; // okay
+}

Propchange: cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/class.derived/class.virtual/p2.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list