From: David Majnemer Date: Thu, 11 Sep 2014 23:05:02 +0000 (+0000) Subject: MS ABI: Use the correct this arg when generating implict copy ctor X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=82903d62ebe3245a16b2086bf702990ca56401e3;p=clang MS ABI: Use the correct this arg when generating implict copy ctor We assumed that the incoming this argument would be the last argument. However, this is not true under the MS ABI. This fixes PR20897. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217642 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index fe331795e9..cf2cccd991 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -384,6 +384,9 @@ public: virtual void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResultType); + virtual size_t getSrcArgforCopyCtor(const CXXConstructorDecl *, + FunctionArgList &Args) const = 0; + /// Gets the pure virtual member call function. virtual StringRef GetPureVirtualCallName() = 0; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 1de325feea..72869d8ca9 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -914,11 +914,12 @@ namespace { private: /// Get source argument for copy constructor. Returns null if not a copy - /// constructor. - static const VarDecl* getTrivialCopySource(const CXXConstructorDecl *CD, + /// constructor. + static const VarDecl *getTrivialCopySource(CodeGenFunction &CGF, + const CXXConstructorDecl *CD, FunctionArgList &Args) { if (CD->isCopyOrMoveConstructor() && CD->isDefaulted()) - return Args[Args.size() - 1]; + return Args[CGF.CGM.getCXXABI().getSrcArgforCopyCtor(CD, Args)]; return nullptr; } @@ -949,7 +950,7 @@ namespace { public: ConstructorMemcpyizer(CodeGenFunction &CGF, const CXXConstructorDecl *CD, FunctionArgList &Args) - : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CD, Args)), + : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CGF, CD, Args)), ConstructorDecl(CD), MemcpyableCtor(CD->isDefaulted() && CD->isCopyOrMoveConstructor() && diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 25e2715daa..bcc0f16620 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -208,6 +208,12 @@ public: llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret, const ReturnAdjustment &RA) override; + size_t getSrcArgforCopyCtor(const CXXConstructorDecl *, + FunctionArgList &Args) const override { + assert(!Args.empty() && "expected the arglist to not be empty!"); + return Args.size() - 1; + } + StringRef GetPureVirtualCallName() override { return "__cxa_pure_virtual"; } StringRef GetDeletedVirtualCallName() override { return "__cxa_deleted_virtual"; } diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 173099a6bb..04b7ea08ed 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -50,6 +50,18 @@ public: bool isSRetParameterAfterThis() const override { return true; } + size_t getSrcArgforCopyCtor(const CXXConstructorDecl *CD, + FunctionArgList &Args) const override { + assert(Args.size() >= 2 && + "expected the arglist to have at least two args!"); + // The 'most_derived' parameter goes second if the ctor is variadic and + // has v-bases. + if (CD->getParent()->getNumVBases() > 0 && + CD->getType()->castAs()->isVariadic()) + return 2; + return 1; + } + StringRef GetPureVirtualCallName() override { return "_purecall"; } // No known support for deleted functions in MSVC yet, so this choice is // arbitrary. diff --git a/test/CodeGenCXX/pr20897.cpp b/test/CodeGenCXX/pr20897.cpp new file mode 100644 index 0000000000..06828c0ec0 --- /dev/null +++ b/test/CodeGenCXX/pr20897.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s | FileCheck %s +struct Base {}; + +// __declspec(dllexport) causes us to export the implicit constructor. +struct __declspec(dllexport) Derived : virtual Base { +// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc %struct.Derived* @"\01??0Derived@@QAE@ABU0@@Z" +// CHECK: %[[this:.*]] = load %struct.Derived** {{.*}} +// CHECK-NEXT: store %struct.Derived* %[[this]], %struct.Derived** %[[retval:.*]] +// CHECK: %[[dest_a_gep:.*]] = getelementptr inbounds %struct.Derived* %[[this]], i32 0, i32 1 +// CHECK-NEXT: %[[src_load:.*]] = load %struct.Derived** {{.*}} +// CHECK-NEXT: %[[src_a_gep:.*]] = getelementptr inbounds %struct.Derived* %[[src_load:.*]], i32 0, i32 1 +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[dest_a_gep]], i8* %[[src_a_gep]], i64 1, i32 4, i1 false) +// CHECK-NEXT: %[[dest_this:.*]] = load %struct.Derived** %[[retval]] +// CHECK-NEXT: ret %struct.Derived* %[[dest_this]] + bool a : 1; + bool b : 1; +};