]> granicus.if.org Git - clang/commitdiff
Handle layout of vtables for virtual bases.
authorAnders Carlsson <andersca@mac.com>
Tue, 16 Feb 2010 16:49:35 +0000 (16:49 +0000)
committerAnders Carlsson <andersca@mac.com>
Tue, 16 Feb 2010 16:49:35 +0000 (16:49 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96355 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGVtable.cpp
test/CodeGenCXX/vtable-layout.cpp

index b9d6332b686c926d9b2aa382078087a355bff74f..b60d470b39586a657c113cf9cf585f4f75f4034f 100644 (file)
@@ -831,6 +831,11 @@ private:
   /// subobject.
   void LayoutSecondaryVtables(BaseSubobject Base);
   
+  /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the
+  /// given base (excluding any primary bases).
+  void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, 
+                                    VisitedVirtualBasesSetTy &VBases);
+
 public:
   VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass)
     : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass), 
@@ -1039,7 +1044,8 @@ VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
 void VtableBuilder::LayoutVtable() {
   LayoutPrimaryAndAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0));
   
-  // FIXME: Emit vtables for virtual bases here.
+  VisitedVirtualBasesSetTy VBases;
+  LayoutVtablesForVirtualBases(MostDerivedClass, VBases);
 }
   
 void VtableBuilder::LayoutPrimaryAndAndSecondaryVtables(BaseSubobject Base) {
@@ -1128,6 +1134,40 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base) {
   }
 }
 
+void
+VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, 
+                                            VisitedVirtualBasesSetTy &VBases) {
+  // Itanium C++ ABI 2.5.2:
+  //   Then come the virtual base virtual tables, also in inheritance graph
+  //   order, and again excluding primary bases (which share virtual tables with
+  //   the classes for which they are primary).
+  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+  const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    const CXXRecordDecl *BaseDecl = 
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+    // Check if this base needs a vtable. (If it's virtual, and we haven't
+    // visited it before).
+    if (I->isVirtual() && BaseDecl->isDynamicClass() && 
+        BaseDecl != PrimaryBase && VBases.insert(BaseDecl)) {
+      const ASTRecordLayout &MostDerivedClassLayout =
+        Context.getASTRecordLayout(MostDerivedClass);
+      uint64_t BaseOffset = 
+        MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+      
+      LayoutPrimaryAndAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset));
+    }
+    
+    // We only need to check the base for virtual base vtables if it actually
+    // has virtual bases.
+    if (BaseDecl->getNumVBases())
+      LayoutVtablesForVirtualBases(BaseDecl, VBases);
+  }
+}
+
 /// dumpLayout - Dump the vtable layout.
 void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
   
index b714511a382ecefa72ccebfdb9ad6303ff132664..bb5996707f0a49e2d403bf5d8876c17f608b227c 100644 (file)
@@ -395,3 +395,30 @@ struct C : B {
 void C::f() { }
 
 }
+
+namespace Test11 {
+
+// Very simple test of vtables for virtual bases.
+struct A1 { int a; };
+struct A2 { int b; };
+
+struct B : A1, virtual A2 {
+  int b;
+};
+
+// CHECK:     Vtable for 'Test11::C' (8 entries).
+// CHECK-NEXT:   0 | vbase_offset (24)
+// CHECK-NEXT:   1 | vbase_offset (8)
+// CHECK-NEXT:   2 | offset_to_top (0)
+// CHECK-NEXT:   3 | Test11::C RTTI
+// CHECK-NEXT:       -- (Test11::C, 0) vtable address --
+// CHECK-NEXT:   4 | void Test11::C::f()
+// CHECK-NEXT:   5 | vbase_offset (16)
+// CHECK-NEXT:   6 | offset_to_top (-8)
+// CHECK-NEXT:   7 | Test11::C RTTI
+struct C : virtual B {
+  virtual void f();
+};
+void C::f() { }
+
+}