More work on covariant return types. We now handle non-virtual adjustments fine.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96114 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 8285a1f..7d3f35f 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -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!");
+    if (const CXXMethodDecl *OverriddenMD = 
+        OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+      if (!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD))
+        continue;
+    }
 
-      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;