diff options
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 9 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 12 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/pr20897.cpp | 17 |
5 files changed, 43 insertions, 4 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index fe331795e91..cf2cccd9910 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/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/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 1de325feea3..72869d8ca9b 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/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/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 25e2715daaf..bcc0f166203 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/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/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 173099a6bba..04b7ea08edc 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/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<FunctionProtoType>()->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/clang/test/CodeGenCXX/pr20897.cpp b/clang/test/CodeGenCXX/pr20897.cpp new file mode 100644 index 00000000000..06828c0ec07 --- /dev/null +++ b/clang/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; +}; |