diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2983,9 +2983,9 @@ It instructs the compiler to pass and return the type using the C ABI for the underlying type when the type would otherwise be considered non-trivial for the purpose of calls. -A class annotated with ``trivial_abi`` can have non-trivial destructors or -copy/move constructors without automatically becoming non-trivial for the -purposes of calls. For example: +A class annotated with trivial_abi can have non-trivial destructors or copy/move +constructors or deleted move and copy constructors without automatically +becoming non-trivial for the purposes of calls. For example: .. code-block:: c++ @@ -3011,7 +3011,6 @@ Attribute ``trivial_abi`` has no effect in the following cases: - The class directly declares a virtual base or virtual methods. -- Copy constructors and move constructors of the class are all deleted. - The class has a base class that is non-trivial for the purposes of calls. - The class has a non-static data member whose type is non-trivial for the purposes of calls, which includes: diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3361,7 +3361,6 @@ "'trivial_abi' cannot be applied to %0">, InGroup; def note_cannot_use_trivial_abi_reason : Note< "'trivial_abi' is disallowed on %0 because %select{" - "its copy constructors and move constructors are all deleted|" "it is polymorphic|" "it has a base of a non-trivial class type|it has a virtual base|" "it has a __weak field|it has a field of a non-trivial class type}1">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6412,6 +6412,9 @@ if (D->isDependentType() || D->isInvalidDecl()) return false; + if (D->hasAttr()) + return true; + // Clang <= 4 used the pre-C++11 rule, which ignores move operations. // The PS4 platform ABI follows the behavior of Clang 3.2. if (CCK == TargetInfo::CCK_ClangABI4OrPS4) @@ -9764,32 +9767,9 @@ RD.dropAttr(); }; - // Ill-formed if the copy and move constructors are deleted. - auto HasNonDeletedCopyOrMoveConstructor = [&]() { - // If the type is dependent, then assume it might have - // implicit copy or move ctor because we won't know yet at this point. - if (RD.isDependentType()) - return true; - if (RD.needsImplicitCopyConstructor() && - !RD.defaultedCopyConstructorIsDeleted()) - return true; - if (RD.needsImplicitMoveConstructor() && - !RD.defaultedMoveConstructorIsDeleted()) - return true; - for (const CXXConstructorDecl *CD : RD.ctors()) - if (CD->isCopyOrMoveConstructor() && !CD->isDeleted()) - return true; - return false; - }; - - if (!HasNonDeletedCopyOrMoveConstructor()) { - PrintDiagAndRemoveAttr(0); - return; - } - // Ill-formed if the struct has virtual functions. if (RD.isPolymorphic()) { - PrintDiagAndRemoveAttr(1); + PrintDiagAndRemoveAttr(0); return; } @@ -9798,12 +9778,12 @@ // virtual base. if (!B.getType()->isDependentType() && !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) { - PrintDiagAndRemoveAttr(2); + PrintDiagAndRemoveAttr(1); return; } if (B.isVirtual()) { - PrintDiagAndRemoveAttr(3); + PrintDiagAndRemoveAttr(2); return; } } @@ -9813,14 +9793,14 @@ // non-trivial for the purpose of calls. QualType FT = FD->getType(); if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) { - PrintDiagAndRemoveAttr(4); + PrintDiagAndRemoveAttr(3); return; } if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs()) if (!RT->isDependentType() && !cast(RT->getDecl())->canPassInRegisters()) { - PrintDiagAndRemoveAttr(5); + PrintDiagAndRemoveAttr(4); return; } } diff --git a/clang/test/CodeGenCXX/trivial_abi.cpp b/clang/test/CodeGenCXX/trivial_abi.cpp --- a/clang/test/CodeGenCXX/trivial_abi.cpp +++ b/clang/test/CodeGenCXX/trivial_abi.cpp @@ -5,6 +5,9 @@ // CHECK: %[[STRUCT_LARGE:.*]] = type { i32*, [128 x i32] } // CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 } // CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { i32 } +// CHECK: [[STRUCT_COPY_MOVE_DELETED:%.*]] = type { i8 } +// CHECK: [[STRUCT_MOVE_LIKE_1:%.*]] = type { i8 } +// CHECK: [[STRUCT_MOVE_LIKE_2:%.*]] = type { i8 } struct __attribute__((trivial_abi)) Small { int *p; @@ -55,6 +58,26 @@ Small m0() override; }; +struct __attribute__((trivial_abi)) CopyMoveDeleted { + CopyMoveDeleted(CopyMoveDeleted const&) = delete; + CopyMoveDeleted(CopyMoveDeleted &&) = delete; + CopyMoveDeleted(int) {} + ~CopyMoveDeleted() {} +}; + +struct __attribute__((trivial_abi)) TemplatedMoveLikeCtor { + TemplatedMoveLikeCtor(TemplatedMoveLikeCtor const&) = delete; + TemplatedMoveLikeCtor(TemplatedMoveLikeCtor &&) = delete; + template TemplatedMoveLikeCtor(T&&) { } + ~TemplatedMoveLikeCtor() {} +}; + +struct __attribute__((trivial_abi)) TemplatedMoveLikeCtor2 { + TemplatedMoveLikeCtor2(TemplatedMoveLikeCtor2 const&) = delete; + template TemplatedMoveLikeCtor2(TemplatedMoveLikeCtor2&&) { } + ~TemplatedMoveLikeCtor2() {} +}; + // CHECK-LABEL: define i64 @_ZThn8_N2D02m0Ev( // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL]], align 8 // CHECK: %[[CALL:.*]] = tail call i64 @_ZN2D02m0Ev( @@ -262,3 +285,22 @@ void testExceptionLarge() { calleeExceptionLarge(Large(), Large()); } + +// CHECK-LABEL: define void @_Z19testCopyMoveDeleted15CopyMoveDeleted(i8 %{{.*}}) +// CHECK: call [[STRUCT_COPY_MOVE_DELETED]]* @_ZN15CopyMoveDeletedD1Ev([[STRUCT_COPY_MOVE_DELETED]]* +// CHECK: ret void +void testCopyMoveDeleted(CopyMoveDeleted ) { } + +// CHECK-LABEL: define void @_Z25testTemplatedMoveLikeCtor21TemplatedMoveLikeCtor(i8 %{{.*}}) +// CHECK: call [[STRUCT_MOVE_LIKE_1]]* @_ZN21TemplatedMoveLikeCtorD1Ev([[STRUCT_MOVE_LIKE_1]]* +// CHECK: ret void +TemplatedMoveLikeCtor testTemplatedMoveLikeCtor(TemplatedMoveLikeCtor a) { + return a; +} + +// CHECK: define void @_Z26testTemplatedMoveLikeCtor222TemplatedMoveLikeCtor2(i8 %{{.*}}) +// CHECK: call [[STRUCT_MOVE_LIKE_2]]* @_ZN22TemplatedMoveLikeCtor2D1Ev([[STRUCT_MOVE_LIKE_2]]* +// CHECK: ret void +TemplatedMoveLikeCtor2 testTemplatedMoveLikeCtor2(TemplatedMoveLikeCtor2 a) { + return a; +} diff --git a/clang/test/SemaCXX/attr-trivial-abi.cpp b/clang/test/SemaCXX/attr-trivial-abi.cpp --- a/clang/test/SemaCXX/attr-trivial-abi.cpp +++ b/clang/test/SemaCXX/attr-trivial-abi.cpp @@ -79,34 +79,3 @@ }; S17 s17; - -namespace deletedCopyMoveConstructor { -struct __attribute__((trivial_abi)) CopyMoveDeleted { // expected-warning {{'trivial_abi' cannot be applied to 'CopyMoveDeleted'}} expected-note {{copy constructors and move constructors are all deleted}} - CopyMoveDeleted(const CopyMoveDeleted &) = delete; - CopyMoveDeleted(CopyMoveDeleted &&) = delete; -}; - -struct __attribute__((trivial_abi)) S18 { // expected-warning {{'trivial_abi' cannot be applied to 'S18'}} expected-note {{copy constructors and move constructors are all deleted}} - CopyMoveDeleted a; -}; - -struct __attribute__((trivial_abi)) CopyDeleted { - CopyDeleted(const CopyDeleted &) = delete; - CopyDeleted(CopyDeleted &&) = default; -}; - -struct __attribute__((trivial_abi)) MoveDeleted { - MoveDeleted(const MoveDeleted &) = default; - MoveDeleted(MoveDeleted &&) = delete; -}; - -struct __attribute__((trivial_abi)) S19 { // expected-warning {{'trivial_abi' cannot be applied to 'S19'}} expected-note {{copy constructors and move constructors are all deleted}} - CopyDeleted a; - MoveDeleted b; -}; - -// This is fine since the move constructor isn't deleted. -struct __attribute__((trivial_abi)) S20 { - int &&a; // a member of rvalue reference type deletes the copy constructor. -}; -} // namespace deletedCopyMoveConstructor diff --git a/clang/test/SemaObjCXX/attr-trivial-abi.mm b/clang/test/SemaObjCXX/attr-trivial-abi.mm --- a/clang/test/SemaObjCXX/attr-trivial-abi.mm +++ b/clang/test/SemaObjCXX/attr-trivial-abi.mm @@ -101,34 +101,3 @@ }; S17 s17; - -namespace deletedCopyMoveConstructor { - struct __attribute__((trivial_abi)) CopyMoveDeleted { // expected-warning {{'trivial_abi' cannot be applied to 'CopyMoveDeleted'}} expected-note {{copy constructors and move constructors are all deleted}} - CopyMoveDeleted(const CopyMoveDeleted &) = delete; - CopyMoveDeleted(CopyMoveDeleted &&) = delete; - }; - - struct __attribute__((trivial_abi)) S18 { // expected-warning {{'trivial_abi' cannot be applied to 'S18'}} expected-note {{copy constructors and move constructors are all deleted}} - CopyMoveDeleted a; - }; - - struct __attribute__((trivial_abi)) CopyDeleted { - CopyDeleted(const CopyDeleted &) = delete; - CopyDeleted(CopyDeleted &&) = default; - }; - - struct __attribute__((trivial_abi)) MoveDeleted { - MoveDeleted(const MoveDeleted &) = default; - MoveDeleted(MoveDeleted &&) = delete; - }; - - struct __attribute__((trivial_abi)) S19 { // expected-warning {{'trivial_abi' cannot be applied to 'S19'}} expected-note {{copy constructors and move constructors are all deleted}} - CopyDeleted a; - MoveDeleted b; - }; - - // This is fine since the move constructor isn't deleted. - struct __attribute__((trivial_abi)) S20 { - int &&a; // a member of rvalue reference type deletes the copy constructor. - }; -}