Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -2566,6 +2566,7 @@ Attribute ``trivial_abi`` has no effect in the following cases: - The class directly declares a virtual base or virtual methods. +- The class doesn't have a copy or move constructor that isn't 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: Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2946,6 +2946,11 @@ def ext_cannot_use_trivial_abi : ExtWarn< "'trivial_abi' cannot be applied to %0">, InGroup; +def note_cannot_use_trivial_abi_reason : Note< + "'trivial_abi' is disallowed on classes that %select{" + "don't have non-deleted copy/move constructors|are polymorphic|" + "have bases of non-trivial class types|have virtual bases|" + "have __weak fields under ARC|have fields of non-trivial class types}0">; // Availability attribute def warn_availability_unknown_platform : Warning< Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -7860,27 +7860,53 @@ } void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { - auto PrintDiagAndRemoveAttr = [&]() { + auto PrintDiagAndRemoveAttr = [&](unsigned N) { // No diagnostics if this is a template instantiation. - if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) + if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) { Diag(RD.getAttr()->getLocation(), diag::ext_cannot_use_trivial_abi) << &RD; + Diag(RD.getAttr()->getLocation(), + diag::note_cannot_use_trivial_abi_reason) << N; + } RD.dropAttr(); }; + // Ill-formed if the copy and move constructors are deleted. + auto HasNonDeletedCopyOrMoveConstructor = [&]() { + 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(); + PrintDiagAndRemoveAttr(1); return; } for (const auto &B : RD.bases()) { // Ill-formed if the base class is non-trivial for the purpose of calls or a // virtual base. - if ((!B.getType()->isDependentType() && - !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) || - B.isVirtual()) { - PrintDiagAndRemoveAttr(); + if (!B.getType()->isDependentType() && + !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) { + PrintDiagAndRemoveAttr(2); + return; + } + + if (B.isVirtual()) { + PrintDiagAndRemoveAttr(3); return; } } @@ -7890,14 +7916,14 @@ // non-trivial for the purpose of calls. QualType FT = FD->getType(); if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(4); return; } if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs()) if (!RT->isDependentType() && !cast(RT->getDecl())->canPassInRegisters()) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(5); return; } } Index: test/SemaObjCXX/attr-trivial-abi.mm =================================================================== --- test/SemaObjCXX/attr-trivial-abi.mm +++ test/SemaObjCXX/attr-trivial-abi.mm @@ -10,23 +10,23 @@ int a; }; -struct __attribute__((trivial_abi)) S2 { // expected-warning {{'trivial_abi' cannot be applied to 'S2'}} +struct __attribute__((trivial_abi)) S2 { // expected-warning {{'trivial_abi' cannot be applied to 'S2'}} expected-note {{have __weak fields under ARC}} __weak id a; }; -struct __attribute__((trivial_abi)) S3 { // expected-warning {{'trivial_abi' cannot be applied to 'S3'}} +struct __attribute__((trivial_abi)) S3 { // expected-warning {{'trivial_abi' cannot be applied to 'S3'}} expected-note {{are polymorphic}} virtual void m(); }; struct S3_2 { virtual void m(); -} __attribute__((trivial_abi)); // expected-warning {{'trivial_abi' cannot be applied to 'S3_2'}} +} __attribute__((trivial_abi)); // expected-warning {{'trivial_abi' cannot be applied to 'S3_2'}} expected-note {{are polymorphic}} struct S4 { int a; }; -struct __attribute__((trivial_abi)) S5 : public virtual S4 { // expected-warning {{'trivial_abi' cannot be applied to 'S5'}} +struct __attribute__((trivial_abi)) S5 : public virtual S4 { // expected-warning {{'trivial_abi' cannot be applied to 'S5'}} expected-note {{have virtual bases}} }; struct __attribute__((trivial_abi)) S9 : public S4 { @@ -36,19 +36,19 @@ __weak id a; }; -struct __attribute__((trivial_abi)) S12 { // expected-warning {{'trivial_abi' cannot be applied to 'S12'}} +struct __attribute__((trivial_abi)) S12 { // expected-warning {{'trivial_abi' cannot be applied to 'S12'}} expected-note {{have __weak fields under ARC}} __weak id a; }; -struct __attribute__((trivial_abi)) S13 { // expected-warning {{'trivial_abi' cannot be applied to 'S13'}} +struct __attribute__((trivial_abi)) S13 { // expected-warning {{'trivial_abi' cannot be applied to 'S13'}} expected-note {{have __weak fields under ARC}} __weak id a[2]; }; -struct __attribute__((trivial_abi)) S7 { // expected-warning {{'trivial_abi' cannot be applied to 'S7'}} +struct __attribute__((trivial_abi)) S7 { // expected-warning {{'trivial_abi' cannot be applied to 'S7'}} expected-note {{have fields of non-trivial class types}} S6 a; }; -struct __attribute__((trivial_abi)) S11 { // expected-warning {{'trivial_abi' cannot be applied to 'S11'}} +struct __attribute__((trivial_abi)) S11 { // expected-warning {{'trivial_abi' cannot be applied to 'S11'}} expected-note {{have fields of non-trivial class types}} S6 a[2]; }; @@ -66,7 +66,7 @@ S10<__weak id> p2; template<> -struct __attribute__((trivial_abi)) S10 { // expected-warning {{'trivial_abi' cannot be applied to 'S10'}} +struct __attribute__((trivial_abi)) S10 { // expected-warning {{'trivial_abi' cannot be applied to 'S10'}} expected-note {{have __weak fields under ARC}} __weak id a; }; @@ -90,8 +90,41 @@ S16 s16; template -struct __attribute__((trivial_abi)) S17 { // expected-warning {{'trivial_abi' cannot be applied to 'S17'}} +struct __attribute__((trivial_abi)) S17 { // expected-warning {{'trivial_abi' cannot be applied to 'S17'}} expected-note {{have __weak fields under ARC}} __weak id a; }; S17 s17; + +namespace deletedCopyMoveConstructor { + struct __attribute__((trivial_abi)) CopyMoveDeleted { // expected-warning {{'trivial_abi' cannot be applied to 'CopyMoveDeleted'}} expected-note {{"don't have non-deleted copy/move constructors}} + CopyMoveDeleted(const CopyMoveDeleted &) = delete; + CopyMoveDeleted(CopyMoveDeleted &&) = delete; + }; + + struct __attribute__((trivial_abi)) S18 { // expected-warning {{'trivial_abi' cannot be applied to 'S18'}} expected-note {{"don't have non-deleted copy/move constructors}} + CopyMoveDeleted a; + S18(const S18 &); + S18(S18 &&); + }; + + 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 {{"don't have non-deleted copy/move constructors}} + 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. + }; +}