zoecarver updated this revision to Diff 324875.
zoecarver added a comment.
- * Format with clang-format.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D92361/new/
https://reviews.llvm.org/D92361
Files:
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CodeGenCXX/trivial_abi.cpp
clang/test/SemaCXX/attr-trivial-abi.cpp
clang/test/SemaObjCXX/attr-trivial-abi.mm
Index: clang/test/SemaObjCXX/attr-trivial-abi.mm
===================================================================
--- clang/test/SemaObjCXX/attr-trivial-abi.mm
+++ clang/test/SemaObjCXX/attr-trivial-abi.mm
@@ -101,34 +101,3 @@
};
S17<int> 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.
- };
-}
Index: clang/test/SemaCXX/attr-trivial-abi.cpp
===================================================================
--- clang/test/SemaCXX/attr-trivial-abi.cpp
+++ clang/test/SemaCXX/attr-trivial-abi.cpp
@@ -34,6 +34,21 @@
S3_2 s32;
};
+struct NonTrivial {
+ NonTrivial(const NonTrivial &) {}
+ ~NonTrivial() {}
+};
+
+struct __attribute__((trivial_abi)) S18 { // expected-warning {{'trivial_abi' cannot be applied to 'S18'}} expected-note {{has a field of a non-trivial class type}}
+ NonTrivial n;
+ ~S18() {}
+};
+
+struct __attribute__((trivial_abi)) S19 : NonTrivial { // expected-warning {{'trivial_abi' cannot be applied to 'S19'}} expected-note {{'trivial_abi' is disallowed on 'S19' because it has a base of a non-trivial class type}}
+ int n;
+ ~S19() {}
+};
+
struct S4 {
int a;
};
@@ -79,34 +94,3 @@
};
S17<int> 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
Index: clang/test/CodeGenCXX/trivial_abi.cpp
===================================================================
--- clang/test/CodeGenCXX/trivial_abi.cpp
+++ clang/test/CodeGenCXX/trivial_abi.cpp
@@ -1,10 +1,19 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-NEW-ABI
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++20 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-20 %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -std=c++20 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-X86 %s
+
// CHECK: %[[STRUCT_SMALL:.*]] = type { i32* }
// 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 }
+// CHECK: [[STRUCT_HAS_MEMBER_COPY_MOVE_DELETED:%.*]] = type { [[STRUCT_COPY_MOVE_DELETED]] }
+// CHECK: [[STRUCT_TEMPLATED_NON_TRIVIAL:%.*]] = type { %[[STRUCT_NONTRIVIAL]] }
+// CHECK: [[STRUCT_TEMPLATED_BASE_NON_TRIVIAL:%.*]] = type { %[[STRUCT_NONTRIVIAL]], i32 }
struct __attribute__((trivial_abi)) Small {
int *p;
@@ -55,6 +64,56 @@
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;
+ template <class T> TemplatedMoveLikeCtor(T &&) {}
+ ~TemplatedMoveLikeCtor() {}
+};
+
+struct __attribute__((trivial_abi)) TemplatedMoveLikeCtor2 {
+ TemplatedMoveLikeCtor2(TemplatedMoveLikeCtor2 const &) = delete;
+ template <class = int> TemplatedMoveLikeCtor2(TemplatedMoveLikeCtor2 &&) {}
+ ~TemplatedMoveLikeCtor2() {}
+};
+
+struct __attribute__((trivial_abi)) HasMemberCopyMoveDeleted {
+ CopyMoveDeleted member;
+};
+
+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)) HasMembersCopyDeletedAndMoveDeleted {
+ CopyDeleted m1;
+ MoveDeleted m2;
+};
+
+template <class T>
+struct __attribute__((trivial_abi)) TemplatedTrivialABI {
+ T n;
+ ~TemplatedTrivialABI() {}
+};
+
+template <class T>
+struct __attribute__((trivial_abi)) TemplatedBaseTrivialABI : T {
+ int n;
+ ~TemplatedBaseTrivialABI() {}
+};
+
// CHECK-LABEL: define{{.*}} i64 @_ZThn8_N2D02m0Ev(
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: %[[CALL:.*]] = tail call i64 @_ZN2D02m0Ev(
@@ -262,3 +321,236 @@
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;
+}
+
+// CHECK: define{{.*}} void @_Z28testHasMemberCopyMoveDeleted24HasMemberCopyMoveDeleted(i64 %{{.*}})
+// CHECK: call [[STRUCT_HAS_MEMBER_COPY_MOVE_DELETED]]* @_ZN24HasMemberCopyMoveDeletedD1Ev([[STRUCT_HAS_MEMBER_COPY_MOVE_DELETED]]*
+// CHECK: ret void
+void testHasMemberCopyMoveDeleted(HasMemberCopyMoveDeleted) {}
+
+// CHECK: define{{.*}} void @_Z39testHasMembersCopyDeletedAndMoveDeleted35HasMembersCopyDeletedAndMoveDeleted(i64 %{{.*}})
+// CHECK: ret void
+void testHasMembersCopyDeletedAndMoveDeleted(HasMembersCopyDeletedAndMoveDeleted) {}
+
+// CHECK: define{{.*}} void @_Z23testTemplatedTrivialABI19TemplatedTrivialABII10NonTrivialE([[STRUCT_TEMPLATED_NON_TRIVIAL]]*
+// CHECK: ret void
+void testTemplatedTrivialABI(TemplatedTrivialABI<NonTrivial> a) {}
+
+// CHECK: define{{.*}} void @_Z27testTemplatedBaseTrivialABI23TemplatedBaseTrivialABII10NonTrivialE([[STRUCT_TEMPLATED_BASE_NON_TRIVIAL]]*
+// CHECK: ret void
+void testTemplatedBaseTrivialABI(TemplatedBaseTrivialABI<NonTrivial> a) {}
+
+namespace DeletedCopyCtor {
+
+struct __attribute__((trivial_abi)) S0 {
+ S0();
+ S0(const S0 &) = delete;
+ S0(S0 &&) = delete;
+ int a;
+};
+struct S1 : S0 {};
+struct S2 : virtual S0 {};
+struct S3 {
+ S0 s0;
+};
+struct S4 {
+ S0 s0;
+ virtual void test();
+};
+struct S5 {
+ S0 s0;
+ S5(S5 const &);
+};
+struct S6 {
+ S0 s0;
+ S6(S6 const &) = delete;
+};
+struct S7 {
+ S0 s0;
+ S7(S7 const &) = default;
+};
+struct S8 : S0 {
+ virtual void test();
+};
+struct S9 : S0 {
+ S9(S9 const &);
+};
+struct S10 : S0 {
+ S10(S10 const &) = delete;
+};
+struct S11 : S0 {
+ S11(S11 const &) = default;
+};
+
+struct S19 { };
+struct S20 : S19, S0 { };
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S0E(i64
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S0E(i64
+// CHECK: ret void
+void test(S0) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S1E(i64
+// CHECK-20: ret void
+void test(S1) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S2E(%"struct.DeletedCopyCtor::S2"*
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S2E(%"struct.DeletedCopyCtor::S2"*
+// CHECK: ret void
+void test(S2) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S3E(i64
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S3E(i64
+// CHECK: ret void
+void test(S3) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S4E(%"struct.DeletedCopyCtor::S4"*
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S4E(%"struct.DeletedCopyCtor::S4"*
+// CHECK: ret void
+void test(S4) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S5E(%"struct.DeletedCopyCtor::S5"*
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S5E(%"struct.DeletedCopyCtor::S5"*
+// CHECK: ret void
+void test(S5) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S6E(%"struct.DeletedCopyCtor::S6"*
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S6E(%"struct.DeletedCopyCtor::S6"*
+// CHECK-NEW-ABI: ret void
+void test(S6) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S7E(%"struct.DeletedCopyCtor::S7"*
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S7E(%"struct.DeletedCopyCtor::S7"*
+// CHECK-NEW-ABI: ret void
+void test(S7) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S8E(%"struct.DeletedCopyCtor::S8"*
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S8E(%"struct.DeletedCopyCtor::S8"*
+// CHECK: ret void
+void test(S8) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S9E(%"struct.DeletedCopyCtor::S9"*
+// CHECK-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_2S9E(%"struct.DeletedCopyCtor::S9"*
+// CHECK: ret void
+void test(S9) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S10E(%"struct.DeletedCopyCtor::S10"*
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S10E(%"struct.DeletedCopyCtor::S10"*
+// CHECK-NEW-ABI: ret void
+void test(S10) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S11E(%"struct.DeletedCopyCtor::S11"*
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S11E(%"struct.DeletedCopyCtor::S11"*
+// CHECK-NEW-ABI: ret void
+void test(S11) {}
+
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S20E(%"struct.DeletedCopyCtor::S20"*
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S20E(%"struct.DeletedCopyCtor::S20"*
+// CHECK-NEW-ABI: ret void
+void test(S20) {}
+
+// Make sure we still pass non-trivial-abi types correctly:
+
+struct S12 {
+ S12();
+ S12(const S12 &) = default;
+ S12(S12 &&);
+};
+
+struct S13 : S12 {
+ S13();
+ S13(const S13 &) = default;
+ S13(S13 &&) = delete;
+};
+
+struct S14 {
+ S14();
+ S14(const S14 &) = default;
+ S14(S14 &&);
+};
+
+struct S15 {
+ S14 s14;
+ S15();
+ S15(const S15 &) = default;
+ S15(S15 &&) = delete;
+};
+
+struct S16 {
+ S16();
+ S16(const S16 &) = default;
+ S16(S16 &&) = delete;
+};
+
+struct S17 {
+ S17();
+ S17(const S17 &) = delete;
+ S17(S17 &&) = default;
+};
+
+struct S18 {
+ S16 a;
+ S17 b;
+};
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S12E(%"struct.DeletedCopyCtor::S12"*
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S12E(%"struct.DeletedCopyCtor::S12"*
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S12E(%"struct.DeletedCopyCtor::S12"*
+// CHECK-X86: ret void
+void test(S12) { }
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S13E(i8
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S13E(i8
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S13E(%"struct.DeletedCopyCtor::S13"* byval(%"struct.DeletedCopyCtor::S13")
+// CHECK-X86: ret void
+void test(S13) { }
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S14E(%"struct.DeletedCopyCtor::S14"*
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S14E(%"struct.DeletedCopyCtor::S14"*
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S14E(%"struct.DeletedCopyCtor::S14"*
+// CHECK-X86: ret void
+void test(S14) { }
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S15E(i64
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S15E(i64
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S15E(%"struct.DeletedCopyCtor::S15"* byval(%"struct.DeletedCopyCtor::S15")
+// CHECK-X86: ret void
+void test(S15) { }
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S16E(i8
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S16E(i8
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S16E()
+// CHECK-X86: ret void
+void test(S16) { }
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S17E(i8
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S17E(i8
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S17E()
+// CHECK-X86: ret void
+void test(S17) { }
+
+// CHECK-NEW-ABI-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S18E(%"struct.DeletedCopyCtor::S18"*
+// CHECK-20-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S18E(%"struct.DeletedCopyCtor::S18"*
+// CHECK-X86-LABEL: define{{.*}} void @_ZN15DeletedCopyCtor4testENS_3S18E(%"struct.DeletedCopyCtor::S18"*
+// CHECK-X86: ret void
+void test(S18) { }
+
+} // namespace DeletedCopyCtor
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -6425,6 +6425,13 @@
if (D->isDependentType() || D->isInvalidDecl())
return false;
+ // If this record has a non-trivial member (or base), the trivial_abi
+ // attribute won't be applied, and we will emit a warning. This means any
+ // record passed to this function can be passed through registers so long as
+ // it still has the trivial_abi attribute.
+ if (D->hasAttr<TrivialABIAttr>())
+ 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)
@@ -6491,6 +6498,50 @@
return false;
}
+ // If all bases and fields are trivial, and all special members are implicit,
+ // then this type can be passed through registers. This might happen if we
+ // have an class that would otherwise be trivial for the purposes of a call
+ // except that it has a non-trivial member *with* the trivial_abi attribute.
+ bool CanPassSubobjects = true;
+ bool AllSubobjectsAreTrivialABI = true;
+ for (auto Base : D->bases()) {
+ if (auto CxxRecord = Base.getType()->getAsCXXRecordDecl()) {
+ AllSubobjectsAreTrivialABI &= CxxRecord->hasAttr<TrivialABIAttr>();
+ if (!canPassInRegisters(S, CxxRecord, CCK)) {
+ CanPassSubobjects = false;
+ break;
+ }
+ }
+ }
+ if (CanPassSubobjects) {
+ for (auto Field : D->fields()) {
+ if (auto CxxRecord = Field->getType()->getAsCXXRecordDecl()) {
+ AllSubobjectsAreTrivialABI &= CxxRecord->hasAttr<TrivialABIAttr>();
+ if (!canPassInRegisters(S, CxxRecord, CCK)) {
+ CanPassSubobjects = false;
+ break;
+ }
+ }
+ }
+ }
+
+ // Intentionally don't check if these are deleted.
+ if (!D->hasUserDeclaredCopyConstructor() &&
+ !D->hasUserDeclaredCopyAssignment() &&
+ !D->hasUserDeclaredMoveOperation() && !D->hasUserDeclaredDestructor() &&
+ D->isAggregate() && CanPassSubobjects) {
+ // If one of these isn't deleted, then this record can be passed in
+ // registers.
+ if (!D->defaultedCopyConstructorIsDeleted() ||
+ !D->defaultedMoveConstructorIsDeleted())
+ return true;
+ // If one of the above conditions is not true, we still might be able to
+ // pass in registers if all of our sub-decls/fields have the trivial_abi
+ // attribute.
+ if (AllSubobjectsAreTrivialABI)
+ return true;
+ }
+
// Per C++ [class.temporary]p3, the relevant condition is:
// each copy constructor, move constructor, and destructor of X is
// either trivial or deleted, and X has at least one non-deleted copy
@@ -9777,32 +9828,9 @@
RD.dropAttr<TrivialABIAttr>();
};
- // 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;
}
@@ -9811,12 +9839,12 @@
// virtual base.
if (!B.getType()->isDependentType() &&
!B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) {
- PrintDiagAndRemoveAttr(2);
+ PrintDiagAndRemoveAttr(1);
return;
}
if (B.isVirtual()) {
- PrintDiagAndRemoveAttr(3);
+ PrintDiagAndRemoveAttr(2);
return;
}
}
@@ -9826,14 +9854,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<RecordType>())
if (!RT->isDependentType() &&
!cast<CXXRecordDecl>(RT->getDecl())->canPassInRegisters()) {
- PrintDiagAndRemoveAttr(5);
+ PrintDiagAndRemoveAttr(4);
return;
}
}
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3381,7 +3381,6 @@
"'trivial_abi' cannot be applied to %0">, InGroup<IgnoredAttributes>;
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">;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -2987,9 +2987,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 (or completely
+deleted) copy/move constructors or a non-trivial destructor without
+automatically becoming non-trivial for the purposes of calls. For example:
.. code-block:: c++
@@ -3015,7 +3015,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:
@@ -3023,6 +3022,11 @@
- classes that are non-trivial for the purposes of calls
- __weak-qualified types in Objective-C++
- arrays of any of the above
+
+Note: If a type has implicitly-deleted copy and move constructors only because
+of a subobject that has the trivial_abi attribute, the type will also be
+considered trivial for the purposes of calls. This requires the type to have no
+user defined special members.
}];
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits