diff options
| author | Peter Collingbourne <peter@pcc.me.uk> | 2016-11-22 00:21:43 +0000 |
|---|---|---|
| committer | Peter Collingbourne <peter@pcc.me.uk> | 2016-11-22 00:21:43 +0000 |
| commit | 120eb54422c0fba462b53cce652a6baef07acf57 (patch) | |
| tree | e43bd370eaee7b24bff7b021cf33dda9205df625 /clang | |
| parent | 5a2e6b97f79d5e345649d50e31c419605462b096 (diff) | |
| download | bcm5719-llvm-120eb54422c0fba462b53cce652a6baef07acf57.tar.gz bcm5719-llvm-120eb54422c0fba462b53cce652a6baef07acf57.zip | |
Sema, CodeGen: Ensure that an implicit copy ctor is available more often under the Microsoft C++ ABI.
This is needed because whether the constructor is deleted can control whether
we pass structs by value directly.
To fix this properly we probably want a more direct way for CodeGen to ask
whether the constructor was deleted.
Fixes PR31049.
Differential Revision: https://reviews.llvm.org/D26822
llvm-svn: 287600
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 25 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 11 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/uncopyable-args.cpp | 61 |
3 files changed, 88 insertions, 9 deletions
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 2722985b2e5..60940fa8fde 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -830,25 +830,32 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const { getContext().getTypeSize(RD->getTypeForDecl()) > 64) return RAA_Indirect; - // We have a trivial copy constructor or no copy constructors, but we have - // to make sure it isn't deleted. - bool CopyDeleted = false; + // If this is true, the implicit copy constructor that Sema would have + // created would not be deleted. FIXME: We should provide a more direct way + // for CodeGen to ask whether the constructor was deleted. + if (!RD->hasUserDeclaredCopyConstructor() && + !RD->hasUserDeclaredMoveConstructor() && + !RD->needsOverloadResolutionForMoveConstructor() && + !RD->hasUserDeclaredMoveAssignment() && + !RD->needsOverloadResolutionForMoveAssignment()) + return RAA_Default; + + // Otherwise, Sema should have created an implicit copy constructor if + // needed. + assert(!RD->needsImplicitCopyConstructor()); + + // We have to make sure the trivial copy constructor isn't deleted. for (const CXXConstructorDecl *CD : RD->ctors()) { if (CD->isCopyConstructor()) { assert(CD->isTrivial()); // We had at least one undeleted trivial copy ctor. Return directly. if (!CD->isDeleted()) return RAA_Default; - CopyDeleted = true; } } // The trivial copy constructor was deleted. Return indirectly. - if (CopyDeleted) - return RAA_Indirect; - - // There were no copy ctors. Return in RAX. - return RAA_Default; + return RAA_Indirect; } llvm_unreachable("invalid enum"); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 82da95e9a67..7d208a43ada 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7396,6 +7396,17 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { if (ClassDecl->needsOverloadResolutionForCopyConstructor() || ClassDecl->hasInheritedConstructor()) DeclareImplicitCopyConstructor(ClassDecl); + // For the MS ABI we need to know whether the copy ctor is deleted. A + // prerequisite for deleting the implicit copy ctor is that the class has a + // move ctor or move assignment that is either user-declared or whose + // semantics are inherited from a subobject. FIXME: We should provide a more + // direct way for CodeGen to ask whether the constructor was deleted. + else if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + (ClassDecl->hasUserDeclaredMoveConstructor() || + ClassDecl->needsOverloadResolutionForMoveConstructor() || + ClassDecl->hasUserDeclaredMoveAssignment() || + ClassDecl->needsOverloadResolutionForMoveAssignment())) + DeclareImplicitCopyConstructor(ClassDecl); } if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) { diff --git a/clang/test/CodeGenCXX/uncopyable-args.cpp b/clang/test/CodeGenCXX/uncopyable-args.cpp index c1d284a7418..9cd57dd01c2 100644 --- a/clang/test/CodeGenCXX/uncopyable-args.cpp +++ b/clang/test/CodeGenCXX/uncopyable-args.cpp @@ -204,3 +204,64 @@ void bar() { // WIN64-LABEL: declare void @"\01?foo@two_copy_ctors@@YAXUB@1@@Z"(%"struct.two_copy_ctors::B"*) } + +namespace definition_only { +struct A { + A(); + A(A &&o); + void *p; +}; +void *foo(A a) { return a.p; } +// WIN64-LABEL: define i8* @"\01?foo@definition_only@@YAPEAXUA@1@@Z"{{.*}} +// WIN64-NEXT: : +// WIN64-NEXT: getelementptr +// WIN64-NEXT: load +} + +namespace deleted_by_member { +struct B { + B(); + B(B &&o); + void *p; +}; +struct A { + A(); + B b; +}; +void *foo(A a) { return a.b.p; } +// WIN64-LABEL: define i8* @"\01?foo@deleted_by_member@@YAPEAXUA@1@@Z"{{.*}} +// WIN64-NEXT: : +// WIN64-NEXT: getelementptr +// WIN64-NEXT: getelementptr +// WIN64-NEXT: load +} + +namespace deleted_by_base { +struct B { + B(); + B(B &&o); + void *p; +}; +struct A : B { + A(); +}; +void *foo(A a) { return a.p; } +// WIN64-LABEL: define i8* @"\01?foo@deleted_by_base@@YAPEAXUA@1@@Z"{{.*}} +// WIN64-NEXT: : +// WIN64-NEXT: bitcast +// WIN64-NEXT: getelementptr +// WIN64-NEXT: load +} + +namespace explicit_delete { +struct A { + A(); + A(const A &o) = delete; + void *p; +}; +// WIN64-LABEL: define i8* @"\01?foo@explicit_delete@@YAPEAXUA@1@@Z"{{.*}} +// WIN64-NEXT: : +// WIN64-NEXT: getelementptr +// WIN64-NEXT: load +void *foo(A a) { return a.p; } +} |

