Generate correct vcall offsets when we have a primary virtual base that is not a primary base in the complete class hierarchy.

llvm-svn: 97039
diff --git a/clang/lib/CodeGen/CGVtable.cpp b/clang/lib/CodeGen/CGVtable.cpp
index 93ed111..61dd11e 100644
--- a/clang/lib/CodeGen/CGVtable.cpp
+++ b/clang/lib/CodeGen/CGVtable.cpp
@@ -968,6 +968,7 @@
   /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
   /// given base subobject.
   void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
+                               uint64_t RealBaseOffset,
                                VisitedVirtualBasesSetTy &VBases);
 
   /// AddVCallOffsets - Add vcall offsets for the given base subobject.
@@ -1112,6 +1113,7 @@
 void 
 VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
                                        bool BaseIsVirtual,
+                                       uint64_t RealBaseOffset,
                                        VisitedVirtualBasesSetTy &VBases) {
   const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase());
   
@@ -1126,8 +1128,28 @@
   // emit them for the primary base first).
   if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
     bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual();
-    AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
-                            PrimaryBaseIsVirtual, VBases);
+
+    uint64_t PrimaryBaseOffset;
+    
+    // Get the base offset of the primary base.
+    if (PrimaryBaseIsVirtual) {
+      assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 &&
+             "Primary vbase should have a zero offset!");
+      
+      const ASTRecordLayout &MostDerivedClassLayout =
+        Context.getASTRecordLayout(MostDerivedClass);
+      
+      PrimaryBaseOffset = 
+        MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
+    } else {
+      assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+             "Primary base should have a zero offset!");
+
+      PrimaryBaseOffset = Base.getBaseOffset();
+    }
+
+    AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
+                            PrimaryBaseIsVirtual, RealBaseOffset, VBases);
   }
 
   // FIXME: Don't use /8 here.
@@ -1136,7 +1158,7 @@
 
   // We only want to add vcall offsets for virtual bases.
   if (BaseIsVirtual)
-    AddVCallOffsets(Base, Base.getBaseOffset());
+    AddVCallOffsets(Base, RealBaseOffset);
 }
 
 void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) {
@@ -1434,7 +1456,7 @@
 
   // Add vcall and vbase offsets for this vtable.
   VisitedVirtualBasesSetTy VBases;
-  AddVCallAndVBaseOffsets(Base, BaseIsVirtual, VBases);
+  AddVCallAndVBaseOffsets(Base, BaseIsVirtual, Base.getBaseOffset(), VBases);
 
   // Reverse them and add them to the vtable components.
   std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end());
@@ -1470,11 +1492,11 @@
     AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint));
   }
 
-  // Layout secondary vtables.
-  LayoutSecondaryVtables(Base);
-  
   // Clear the vcall offsets.
   VCallOffsets.clear();  
+
+  // Layout secondary vtables.
+  LayoutSecondaryVtables(Base);
 }
 
 void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base) {