Fix thunk emission for covariant virtual functions in cases which require
both a virtual and a non-virtual offset. PR13832.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163866 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index afd58e8..43708ff 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -79,15 +79,16 @@
 static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
                                           llvm::Value *Ptr,
                                           int64_t NonVirtualAdjustment,
-                                          int64_t VirtualAdjustment) {
+                                          int64_t VirtualAdjustment,
+                                          bool IsReturnAdjustment) {
   if (!NonVirtualAdjustment && !VirtualAdjustment)
     return Ptr;
 
   llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
   llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
 
-  if (NonVirtualAdjustment) {
-    // Do the non-virtual adjustment.
+  if (NonVirtualAdjustment && !IsReturnAdjustment) {
+    // Perform the non-virtual adjustment for a base-to-derived cast.
     V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
   }
 
@@ -95,7 +96,7 @@
     llvm::Type *PtrDiffTy = 
       CGF.ConvertType(CGF.getContext().getPointerDiffType());
 
-    // Do the virtual adjustment.
+    // Perform the virtual adjustment.
     llvm::Value *VTablePtrPtr = 
       CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
     
@@ -113,6 +114,11 @@
     V = CGF.Builder.CreateInBoundsGEP(V, Offset);
   }
 
+  if (NonVirtualAdjustment && IsReturnAdjustment) {
+    // Perform the non-virtual adjustment for a derived-to-base cast.
+    V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+  }
+
   // Cast back to the original type.
   return CGF.Builder.CreateBitCast(V, Ptr->getType());
 }
@@ -199,7 +205,8 @@
   
   ReturnValue = PerformTypeAdjustment(CGF, ReturnValue, 
                                       Thunk.Return.NonVirtual, 
-                                      Thunk.Return.VBaseOffsetOffset);
+                                      Thunk.Return.VBaseOffsetOffset,
+                                      /*IsReturnAdjustment*/true);
   
   if (NullCheckValue) {
     CGF.Builder.CreateBr(AdjustEnd);
@@ -281,7 +288,8 @@
   llvm::Value *AdjustedThisPtr = 
     PerformTypeAdjustment(*this, ThisPtr, 
                           Thunk.This.NonVirtual, 
-                          Thunk.This.VCallOffsetOffset);
+                          Thunk.This.VCallOffsetOffset,
+                          /*IsReturnAdjustment*/false);
   ThisStore->setOperand(0, AdjustedThisPtr);
 
   if (!Thunk.Return.isEmpty()) {
@@ -335,7 +343,8 @@
   llvm::Value *AdjustedThisPtr = 
     PerformTypeAdjustment(*this, LoadCXXThis(), 
                           Thunk.This.NonVirtual, 
-                          Thunk.This.VCallOffsetOffset);
+                          Thunk.This.VCallOffsetOffset,
+                          /*IsReturnAdjustment*/false);
   
   CallArgList CallArgs;