Refine the vcall for a function that is defined in a virtual base
class that is overridden in a base that isn't morally virtual.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86217 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index e2e1147..34012ca 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -242,15 +242,13 @@
             idx = VCalls.size()+1;
             VCalls.push_back(0);
             D1(printf("  vcall for %s at %d with delta %d most derived %s\n",
-                      MD->getNameAsCString(),
-                      (int)-VCalls.size()-3, (int)VCallOffset[MD],
+                      MD->getNameAsCString(), (int)-idx-3, (int)VCalls[idx-1],
                       Class->getNameAsCString()));
           } else {
             VCallOffset[MD] = VCallOffset[OMD];
             VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8;
             D1(printf("  vcall patch for %s at %d with delta %d most derived %s\n",
-                      MD->getNameAsCString(),
-                      (int)-VCalls.size()-3, (int)VCallOffset[MD],
+                      MD->getNameAsCString(), (int)-idx-3, (int)VCalls[idx-1],
                       Class->getNameAsCString()));
           }
           VCall[MD] = idx;
@@ -271,6 +269,16 @@
         // FIXME: finish off
         int64_t O = VCallOffset[OMD] - OverrideOffset/8;
         // int64_t O = CurrentVBaseOffset/8 - OverrideOffset/8;
+
+        if (VCall.count(OMD)) {
+          VCallOffset[MD] = VCallOffset[OMD];
+          Index_t idx = VCall[OMD];
+          VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8;
+          D1(printf("  vcall patch for %s at %d with delta %d most derived %s\n",
+                    MD->getNameAsCString(), (int)-idx-3, (int)VCalls[idx-1],
+                    Class->getNameAsCString()));
+          VCall[MD] = idx;
+        }        
         if (O || ReturnOffset.first || ReturnOffset.second) {
           CallOffset ThisOffset = std::make_pair(O, 0);
           
@@ -374,8 +382,7 @@
         idx = VCalls.size()+1;
         VCalls.push_back(0);
         D1(printf("  vcall for %s at %d with delta %d\n",
-                  MD->getNameAsCString(), (int)-VCalls.size()-3,
-                  (int)VCallOffset[MD]));
+                  MD->getNameAsCString(), (int)-VCalls.size()-3, 0));
       }
     }
   }
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
index 5eeabfa..0f239ee 100644
--- a/test/CodeGenCXX/virt.cpp
+++ b/test/CodeGenCXX/virt.cpp
@@ -895,7 +895,7 @@
 class test20_B1 : virtual test20_V1 {
 };
 class test20_D : public test20_B, public test20_B1 {
-} d;
+};
 
 // CHECK-LP64: __ZTV8test20_D:
 // CHECK-LP64-NEXT: .quad 8
@@ -911,6 +911,34 @@
 // CHECK-LP64-NEXT: .quad __ZN9test20_V14foo2Ev
 
 
+class test21_V {
+  virtual void foo();
+};
+class test21_V1 {
+  virtual void foo();
+};
+class test21_B : virtual test21_V {
+};
+class test21_B1 : virtual test21_V1 {
+};
+class test21_D : public test21_B, public test21_B1 {
+  void foo() { }
+};
+
+// CHECK-LP64: __ZTV8test21_D:
+// CHECK-LP64-NEXT: .quad 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI8test21_D
+// CHECK-LP64-NEXT: .quad __ZN8test21_D3fooEv
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad 18446744073709551608
+// CHECK-LP64-NEXT: .quad __ZTI8test21_D
+// CHECK-LP64-NEXT .quad __ZTv0_n24_N8test21_D3fooEv
+
+
 
 // CHECK-LP64: __ZTV1B:
 // CHECK-LP64-NEXT: .space 8
@@ -951,6 +979,8 @@
 // CHECK-LP64-NEXT: .quad __ZN2D14bar4Ev
 // CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev
 
+test21_D d21;
+test20_D d20;
 test19_D d19;
 test18_D d18;
 test17_D d17;