]> granicus.if.org Git - clang/commitdiff
Fix thunk emission for covariant virtual functions in cases which require
authorEli Friedman <eli.friedman@gmail.com>
Fri, 14 Sep 2012 01:45:09 +0000 (01:45 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 14 Sep 2012 01:45:09 +0000 (01:45 +0000)
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

lib/CodeGen/CGVTables.cpp
test/CodeGenCXX/thunks.cpp

index afd58e8ae29d69fd60e660270e7b3aab861c9831..43708ff160ff66df9b556a55f21ea01a2e9ba28a 100644 (file)
@@ -79,15 +79,16 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
 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 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
     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 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
     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 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
   
   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 @@ void CodeGenFunction::GenerateVarArgsThunk(
   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 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
   llvm::Value *AdjustedThisPtr = 
     PerformTypeAdjustment(*this, LoadCXXThis(), 
                           Thunk.This.NonVirtual, 
-                          Thunk.This.VCallOffsetOffset);
+                          Thunk.This.VCallOffsetOffset,
+                          /*IsReturnAdjustment*/false);
   
   CallArgList CallArgs;
   
index 04d0820da7a3100a75b5a8f7a4fb3b8e57a3dc0e..bf3b03e4e42430c66dd90500657541db4a21fcd1 100644 (file)
@@ -301,6 +301,32 @@ namespace Test12 {
   // CHECK: getelementptr inbounds i8* {{.*}}, i64 8
 }
 
+// PR13832
+namespace Test13 {
+  struct B1 {
+    virtual B1 &foo1();
+  };
+  struct Pad1 {
+    virtual ~Pad1();
+  };
+  struct Proxy1 : Pad1, B1 {
+    virtual ~Proxy1();
+  };
+  struct D : virtual Proxy1 {
+    virtual ~D();
+    virtual D &foo1();
+  };
+  D& D::foo1() {
+    return *this;
+  }
+  // CHECK: define {{.*}} @_ZTcvn8_n32_v8_n24_N6Test131D4foo1Ev
+  // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+  // CHECK: getelementptr inbounds i8* {{.*}}, i64 -32
+  // CHECK: getelementptr inbounds i8* {{.*}}, i64 -24
+  // CHECK: getelementptr inbounds i8* {{.*}}, i64 8
+  // CHECK: ret %"struct.Test13::D"*
+}
+
 /**** The following has to go at the end of the file ****/
 
 // This is from Test5: