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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to