]> granicus.if.org Git - clang/commitdiff
Make FinalOverriders handle virtual bases correctly. Unfortunately this can't be...
authorAnders Carlsson <andersca@mac.com>
Wed, 17 Feb 2010 17:48:25 +0000 (17:48 +0000)
committerAnders Carlsson <andersca@mac.com>
Wed, 17 Feb 2010 17:48:25 +0000 (17:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96481 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGVtable.cpp

index 58989ede0bc98c617f71d47010ac408285838c11..f5bd33e548fc7d725f6805ff5455bf1120c2addd 100644 (file)
@@ -120,6 +120,7 @@ private:
   /// ComputeFinalOverriders - Compute the final overriders for a given base
   /// subobject (and all its direct and indirect bases).
   void ComputeFinalOverriders(BaseSubobject Base,
+                              bool BaseSubobjectIsVisitedVBase,
                               SubobjectOffsetsMapTy &Offsets);
   
   /// AddOverriders - Add the final overriders for this base subobject to the
@@ -197,7 +198,9 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass)
     
   // Compute the final overriders.
   SubobjectOffsetsMapTy Offsets;
-  ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), Offsets);
+  ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), 
+                         /*BaseSubobjectIsVisitedVBase=*/false, Offsets);
+  VisitedVirtualBases.clear();
     
   // And dump them (for now).
   dump();
@@ -524,6 +527,7 @@ FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
 }
 
 void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
+                                             bool BaseSubobjectIsVisitedVBase,
                                              SubobjectOffsetsMapTy &Offsets) {
   const CXXRecordDecl *RD = Base.getBase();
   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -539,19 +543,45 @@ void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
     if (!BaseDecl->isPolymorphic())
       continue;
     
+    bool IsVisitedVirtualBase = false;
     uint64_t BaseOffset;
     if (I->isVirtual()) {
+      if (!VisitedVirtualBases.insert(BaseDecl))
+        IsVisitedVirtualBase = true;
       BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
     } else {
       BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
     }
     
     // Compute the final overriders for this base.
-    ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), NewOffsets);
+    // We always want to compute the final overriders, even if the base is a
+    // visited virtual base. Consider:
+    //
+    // struct A {
+    //   virtual void f();
+    //   virtual void g();
+    // };
+    //  
+    // struct B : virtual A {
+    //   void f();
+    // };
+    //
+    // struct C : virtual A {
+    //   void g ();
+    // };
+    //
+    // struct D : B, C { };
+    //
+    // Here, we still want to compute the overriders for A as a base of C, 
+    // because otherwise we'll miss that C::g overrides A::f.
+    ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), 
+                           IsVisitedVirtualBase, NewOffsets);                           
   }
 
   /// Now add the overriders for this particular subobject.
-  AddOverriders(Base, NewOffsets);
+  /// (We don't want to do this more than once for a virtual base).
+  if (!BaseSubobjectIsVisitedVBase)
+    AddOverriders(Base, NewOffsets);
   
   // And merge the newly discovered subobject offsets.
   MergeSubobjectOffsets(NewOffsets, Offsets);