[cfe-commits] r96114 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp

Anders Carlsson andersca at mac.com
Sat Feb 13 12:11:51 PST 2010


Author: andersca
Date: Sat Feb 13 14:11:51 2010
New Revision: 96114

URL: http://llvm.org/viewvc/llvm-project?rev=96114&view=rev
Log:
More work on covariant return types. We now handle non-virtual adjustments fine.

Modified:
    cfe/trunk/lib/CodeGen/CGVtable.cpp
    cfe/trunk/test/CodeGenCXX/vtable-layout.cpp

Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96114&r1=96113&r2=96114&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Sat Feb 13 14:11:51 2010
@@ -225,14 +225,19 @@
   
   /// getOverrider - Get the final overrider for the given method declaration in
   /// the given base subobject.
-  const OverriderInfo getOverrider(BaseSubobject Base,
-                                   const CXXMethodDecl *MD) const {
+  OverriderInfo getOverrider(BaseSubobject Base,
+                             const CXXMethodDecl *MD) const {
     assert(OverridersMap.count(std::make_pair(Base, MD)) && 
            "Did not find overrider!");
     
     return OverridersMap.lookup(std::make_pair(Base, MD));
   }
   
+  BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
+                                       const CXXMethodDecl *MD) const {
+    return ReturnAdjustments.lookup(std::make_pair(Base, MD));
+  }
+
   /// dump - dump the final overriders.
   void dump() const { 
       dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0)); 
@@ -469,7 +474,6 @@
 }
 
 void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) const {
-  
   const CXXRecordDecl *RD = Base.getBase();
   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
 
@@ -532,9 +536,6 @@
     CK_DeletingDtorPointer
   };
 
-  /// dump - Dump the contents of this component to the given stream.
-  void dump(llvm::raw_ostream &Out);
-
   static VtableComponent MakeOffsetToTop(int64_t Offset) {
     return VtableComponent(CK_OffsetToTop, Offset);
   }
@@ -670,10 +671,27 @@
     /// VBaseOffsetIndex - The index relative to the address point of the
     /// virtual base class offset.
     int64_t VBaseOffsetIndex;
-  };
     
-  void layoutVirtualMemberFunctions(BaseSubobject Base,
-                                    PrimaryBasesSetTy &PrimaryBases);
+    ReturnAdjustment() : NonVirtual(0), VBaseOffsetIndex(0) { }
+    
+    bool isEmpty() const { return !NonVirtual && !VBaseOffsetIndex; }
+  };
+  
+  /// ReturnAdjustments - The return adjustments needed in this vtable.
+  llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16> 
+    ReturnAdjustments;
+
+  /// ComputeReturnAdjustment - Compute the return adjustment given return
+  /// adjustment base offset.
+  ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
+  
+  /// AddMethod - Add a single virtual member function to the vtable
+  /// components vector.
+  void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
+
+  /// AddMethods - Add the methods of this base subobject and all its
+  /// primary bases to the vtable components vector.
+  void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases);
   
   /// layoutSimpleVtable - A test function that will layout very simple vtables
   /// without any bases. Just used for testing for now.
@@ -711,9 +729,41 @@
   return 0;
 }
 
+VtableBuilder::ReturnAdjustment 
+VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) {
+  ReturnAdjustment Adjustment;
+  
+  if (!Offset.isEmpty()) {
+    assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!");
+
+    Adjustment.NonVirtual = Offset.NonVirtualOffset;
+  }
+  
+  return Adjustment;
+}
+
 void 
-VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
-                                            PrimaryBasesSetTy &PrimaryBases) {
+VtableBuilder::AddMethod(const CXXMethodDecl *MD,
+                         ReturnAdjustment ReturnAdjustment) {
+  if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+    assert(ReturnAdjustment.isEmpty() && 
+           "Destructor can't have return adjustment!");
+    // Add both the complete destructor and the deleting destructor.
+    Components.push_back(VtableComponent::MakeCompleteDtor(DD));
+    Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+  } else {
+    // Add the return adjustment if necessary.
+    if (!ReturnAdjustment.isEmpty())
+      ReturnAdjustments.push_back(std::make_pair(Components.size(),
+                                                 ReturnAdjustment));
+
+    // Add the function.
+    Components.push_back(VtableComponent::MakeFunction(MD));
+  }
+}
+
+void 
+VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
   const CXXRecordDecl *RD = Base.getBase();
 
   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -725,7 +775,7 @@
       assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
              "Primary base should have a zero offset!");
     
-    layoutVirtualMemberFunctions(BaseSubobject(PrimaryBase, 0), PrimaryBases);
+    AddMethods(BaseSubobject(PrimaryBase, 0), PrimaryBases);
     
     if (!PrimaryBases.insert(PrimaryBase))
       assert(false && "Found a duplicate primary base!");
@@ -746,22 +796,20 @@
     // Check if this virtual member function overrides a method in a primary
     // base. If this is the case, and the return type doesn't require adjustment
     // then we can just use the member function from the primary base.
-    if (const CXXMethodDecl *OverriddenMD ATTRIBUTE_UNUSED = 
-          OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
-      assert(!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD)
-             && "FIXME: Handle covariant thunks!");
-
-      continue;
+    if (const CXXMethodDecl *OverriddenMD = 
+        OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+      if (!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD))
+        continue;
     }
+
+    // Check if this overrider needs a return adjustment.
+    FinalOverriders::BaseOffset ReturnAdjustmentOffset = 
+      Overriders.getReturnAdjustmentOffset(Base, MD);
+
+    ReturnAdjustment ReturnAdjustment = 
+      ComputeReturnAdjustment(ReturnAdjustmentOffset);
     
-    if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
-      // Add both the complete destructor and the deleting destructor.
-      Components.push_back(VtableComponent::MakeCompleteDtor(DD));
-      Components.push_back(VtableComponent::MakeDeletingDtor(DD));
-    } else {
-      // Add the function.
-      Components.push_back(VtableComponent::MakeFunction(MD));
-    }
+    AddMethod(Overrider.Method, ReturnAdjustment);
   }
 }
 
@@ -778,7 +826,7 @@
 
   // Now go through all virtual member functions and add them.
   PrimaryBasesSetTy PrimaryBases;
-  layoutVirtualMemberFunctions(Base, PrimaryBases);
+  AddMethods(Base, PrimaryBases);
 
   // Record the address point.
   AddressPoints.insert(std::make_pair(Base, AddressPoint));
@@ -832,6 +880,7 @@
     AddressPointsByIndex.insert(std::make_pair(Index, Base));
   }
   
+  unsigned NextReturnAdjustmentIndex = 0;
   for (unsigned I = 0, E = Components.size(); I != E; ++I) {
     uint64_t Index = I;
     
@@ -895,6 +944,20 @@
       if (MD->isPure())
         Out << " [pure]";
 
+      // If this function pointer has a return adjustment thunk, dump it.
+      if (NextReturnAdjustmentIndex < ReturnAdjustments.size() && 
+          ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
+        const ReturnAdjustment Adjustment = 
+          ReturnAdjustments[NextReturnAdjustmentIndex].second;
+        
+        assert(!Adjustment.VBaseOffsetIndex && "FIXME: Handle virtual bases!");
+        
+        Out << "\n       [return adjustment: ";
+        Out << Adjustment.NonVirtual << " non-virtual]";
+
+        NextReturnAdjustmentIndex++;
+      }
+
       break;
     }
 
@@ -2186,6 +2249,12 @@
   }
   
   I = VirtualBaseClassIndicies.find(ClassPair);
+  // FIXME: The assertion below assertion currently fails with the old vtable 
+  /// layout code if there is a non-virtual thunk adjustment in a vtable.
+  // Once the new layout is in place, this return should be removed.
+  if (I == VirtualBaseClassIndicies.end())
+    return 0;
+  
   assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
   
   return I->second;

Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=96114&r1=96113&r2=96114&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Sat Feb 13 14:11:51 2010
@@ -78,7 +78,7 @@
 // CHECK-NEXT:  1 | Test3::B RTTI
 // CHECK-NEXT:      -- (Test3::A, 0) vtable address --
 // CHECK-NEXT:      -- (Test3::B, 0) vtable address --
-// CHECK-NEXT:  2 | void Test3::A::f()
+// CHECK-NEXT:  2 | void Test3::B::f()
 // CHECK-NEXT:  3 | void Test3::B::g()
 struct B : A {
   virtual void f();
@@ -106,8 +106,8 @@
 // CHECK-NEXT:     -- (Test3::A, 0) vtable address --
 // CHECK-NEXT:     -- (Test3::B, 0) vtable address --
 // CHECK-NEXT:     -- (Test3::D, 0) vtable address --
-// CHECK-NEXT:  2 | void Test3::A::f()
-// CHECK-NEXT:  3 | void Test3::B::g()
+// CHECK-NEXT:  2 | void Test3::D::f()
+// CHECK-NEXT:  3 | void Test3::D::g()
 // CHECK-NEXT:  4 | void Test3::D::h()
 struct D : B {
   virtual void f();
@@ -118,6 +118,35 @@
 void D::f() { } 
 }
 
+namespace Test4 {
+
+// Test simple non-virtual result adjustments.
+
+struct R1 { int r1; };
+struct R2 { int r2; };
+struct R3 : R1, R2 { int r3; };
+
+struct A {
+  virtual R2 *f();
+};
+
+// CHECK:     Vtable for 'Test4::B' (4 entries).
+// CHECK-NEXT:  0 | offset_to_top (0)
+// CHECK-NEXT:  1 | Test4::B RTTI
+// CHECK-NEXT:      -- (Test4::A, 0) vtable address --
+// CHECK-NEXT:      -- (Test4::B, 0) vtable address --
+// CHECK-NEXT:  2 | Test4::R3 *Test4::B::f()
+// CHECK-NEXT:      [return adjustment: 4 non-virtual]
+// CHECK-NEXT:  3 | Test4::R3 *Test4::B::f()
+
+struct B : A {
+  virtual R3 *f();
+};
+
+R3 *B::f() { return 0; }
+  
+}
+
 // For now, just verify this doesn't crash.
 namespace test0 {
   struct Obj {};





More information about the cfe-commits mailing list