]> granicus.if.org Git - clang/commitdiff
Handle diamond inheritance in -Woverloaded-virtual.
authorDavid Blaikie <dblaikie@gmail.com>
Fri, 19 Oct 2012 00:53:08 +0000 (00:53 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Fri, 19 Oct 2012 00:53:08 +0000 (00:53 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166254 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/warn-overloaded-virtual.cpp

index 93b78c1316bcc7d5071651d126177dfe25255ab9..0adcfc15201290f0e30cfe2237399a921ae6ad8e 100644 (file)
@@ -4739,6 +4739,19 @@ namespace {
   };
 }
 
+/// \brief Check whether any most overriden method from MD in Methods
+static bool CheckMostOverridenMethods(const CXXMethodDecl *MD,
+                   const llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+  if (MD->size_overridden_methods() == 0)
+    return Methods.count(MD->getCanonicalDecl());
+  for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+                                      E = MD->end_overridden_methods();
+       I != E; ++I)
+    if (CheckMostOverridenMethods(*I, Methods))
+      return true;
+  return false;
+}
+
 /// \brief Member lookup function that determines whether a given C++
 /// method overloads virtual methods in a base class without overriding any,
 /// to be used with CXXRecordDecl::lookupInBases().
@@ -4770,12 +4783,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
       if (!Data.S->IsOverload(Data.Method, MD, false))
         return true;
       // Collect the overload only if its hidden.
-      bool Using = Data.OverridenAndUsingBaseMethods.count(MD);
-      for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
-                                          E = MD->end_overridden_methods();
-           I != E && !Using; ++I)
-        Using = Data.OverridenAndUsingBaseMethods.count(*I);
-      if (!Using)
+      if (!CheckMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods))
         overloadedMethods.push_back(MD);
     }
   }
@@ -4786,6 +4794,17 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
   return foundSameNameMethod;
 }
 
+/// \brief Add the most overriden methods from MD to Methods
+static void AddMostOverridenMethods(const CXXMethodDecl *MD,
+                         llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+  if (MD->size_overridden_methods() == 0)
+    Methods.insert(MD->getCanonicalDecl());
+  for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+                                      E = MD->end_overridden_methods();
+       I != E; ++I)
+    AddMostOverridenMethods(*I, Methods);
+}
+
 /// \brief See if a method overloads virtual methods in a base class without
 /// overriding any.
 void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4806,14 +4825,11 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
   // by 'using' in a set. A base method not in this set is hidden.
   for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName());
        res.first != res.second; ++res.first) {
-    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*res.first))
-      for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
-                                          E = MD->end_overridden_methods();
-           I != E; ++I)
-        Data.OverridenAndUsingBaseMethods.insert((*I)->getCanonicalDecl());
+    NamedDecl *ND = *res.first;
     if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first))
-      if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(shad->getTargetDecl()))
-        Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl());
+      ND = shad->getTargetDecl();
+    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+      AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods);
   }
 
   if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) &&
index 79635a62f8a47a26fbfe2b466dab821bb50c92e8..9b0f5aa9f339eb673f4db63dddd4ba4f5861c12a 100644 (file)
@@ -80,3 +80,43 @@ struct C: B {
   using A::f;
 };
 }
+
+namespace UnbalancedVirtual {
+struct Base {
+  virtual void func();
+};
+
+struct Derived1: virtual Base {
+  virtual void func();
+};
+
+struct Derived2: virtual Base {
+};
+
+struct MostDerived: Derived1, Derived2 {
+  void func(int);
+  void func();
+};
+}
+
+namespace UnbalancedVirtual2 {
+struct Base {
+  virtual void func();
+};
+
+struct Derived1: virtual Base {
+  virtual void func();
+};
+
+struct Derived2: virtual Base {
+};
+
+struct Derived3: Derived1 {
+  virtual void func();
+};
+
+struct MostDerived: Derived3, Derived2 {
+  void func(int);
+  void func();
+};
+}