From: Eli Friedman Date: Fri, 14 Sep 2012 01:45:09 +0000 (+0000) Subject: Fix thunk emission for covariant virtual functions in cases which require X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=82bad6bbb6c04ec6e34562988d0d1f9e450a7279;p=clang 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 afd58e8ae2..43708ff160 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -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; diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp index 04d0820da7..bf3b03e4e4 100644 --- a/test/CodeGenCXX/thunks.cpp +++ b/test/CodeGenCXX/thunks.cpp @@ -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: