diff --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def index cdf0804680ad0..36d3cfb7dfe85 100644 --- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def +++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def @@ -189,6 +189,11 @@ FIELD(DeclaredNonTrivialSpecialMembers, 6, MERGE_OR) /// SMF_MoveConstructor, and SMF_Destructor are meaningful here. FIELD(DeclaredNonTrivialSpecialMembersForCall, 6, MERGE_OR) +/// True when this class's bases and fields are all trivially relocatable +/// or references, and the class itself has no user-provided special +/// member functions. +FIELD(IsNaturallyTriviallyRelocatable, 1, NO_MERGE) + /// True when this class has a destructor with no semantic effect. FIELD(HasIrrelevantDestructor, 1, NO_MERGE) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 9cebaff63bb0d..a58126c98597b 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1386,6 +1386,9 @@ class CXXRecordDecl : public RecordDecl { (SMF_CopyConstructor | SMF_MoveConstructor | SMF_Destructor); } + /// Determine whether this class is trivially relocatable + bool isTriviallyRelocatable() const; + /// Determine whether declaring a const variable with this type is ok /// per core issue 253. bool allowConstDefaultInit() const { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 1c3dcf63465c6..263db64c330b4 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -95,7 +95,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), HasTrivialSpecialMembersForCall(SMF_All), DeclaredNonTrivialSpecialMembers(0), - DeclaredNonTrivialSpecialMembersForCall(0), HasIrrelevantDestructor(true), + DeclaredNonTrivialSpecialMembersForCall(0), + IsNaturallyTriviallyRelocatable(true), HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), HasDefaultedDefaultConstructor(false), DefaultedDefaultConstructorIsConstexpr(true), @@ -279,6 +280,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // An aggregate is a class with [...] no virtual functions. data().Aggregate = false; + + // A trivially relocatable class is a class: + // -- which has no virtual member functions or virtual base classes + data().IsNaturallyTriviallyRelocatable = false; } // C++0x [class]p7: @@ -293,6 +298,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C)) data().HasNonLiteralTypeFieldsOrBases = true; + if (Base->isVirtual() || !BaseClassDecl->isTriviallyRelocatable()) + data().IsNaturallyTriviallyRelocatable = false; + // Now go through all virtual bases of this base and add them. for (const auto &VBase : BaseClassDecl->vbases()) { // Add this base if it's not already in the list. @@ -572,6 +580,10 @@ bool CXXRecordDecl::hasAnyDependentBases() const { return !forallBases([](const CXXRecordDecl *) { return true; }); } +bool CXXRecordDecl::isTriviallyRelocatable() const { + return (data().IsNaturallyTriviallyRelocatable || hasAttr()); +} + bool CXXRecordDecl::isTriviallyCopyable() const { // C++0x [class]p5: // A trivially copyable class is a class that: @@ -760,6 +772,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // -- has no virtual functions data().IsStandardLayout = false; data().IsCXX11StandardLayout = false; + + // A trivially relocatable class is a class: + // -- which has no virtual member functions or virtual base classes + data().IsNaturallyTriviallyRelocatable = false; } } @@ -1068,6 +1084,12 @@ void CXXRecordDecl::addedMember(Decl *D) { } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; + // A trivially relocatable class is a class: + // -- all of whose members are either of reference type or of trivially + // relocatable type + if (!T->isReferenceType() && !T.isTriviallyRelocatableType(Context)) + data().IsNaturallyTriviallyRelocatable = false; + if (T->isReferenceType()) { if (!Field->hasInClassInitializer()) data().HasUninitializedReferenceMember = true; @@ -1423,8 +1445,9 @@ void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD, // See https://github.com/llvm/llvm-project/issues/59206 if (const auto *DD = dyn_cast(MD)) { - if (DD->isUserProvided()) + if (DD->isUserProvided()) { data().HasIrrelevantDestructor = false; + } // If the destructor is explicitly defaulted and not trivial or not public // or if the destructor is deleted, we clear HasIrrelevantDestructor in // finishedDefaultedOrDeletedMember. @@ -1440,6 +1463,17 @@ void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD, data().IsAnyDestructorNoReturn = true; } + // A trivially relocatable class is a class: + // -- where no eligible copy constructor, move constructor, copy + // assignment operator, move assignment operator, or destructor is + // user-provided, + if (MD->isUserProvided() && + (SMKind & (SMF_CopyConstructor | SMF_MoveConstructor | + SMF_CopyAssignment | SMF_MoveAssignment | SMF_Destructor)) != + 0u) { + data().IsNaturallyTriviallyRelocatable = false; + } + if (!MD->isImplicit() && !MD->isUserProvided()) { // This method is user-declared but not user-provided. We can't work // out whether it's trivial yet (not until we get to the end of the diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 22666184c56cc..58f15ad0ca870 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2680,8 +2680,8 @@ bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const { return false; } else if (!BaseElementType->isObjectType()) { return false; - } else if (const auto *RD = BaseElementType->getAsRecordDecl()) { - return RD->canPassInRegisters(); + } else if (const auto *RD = BaseElementType->getAsCXXRecordDecl()) { + return RD->isTriviallyRelocatable(); } else if (BaseElementType.isTriviallyCopyableType(Context)) { return true; } else { diff --git a/clang/test/SemaCXX/attr-trivial-abi.cpp b/clang/test/SemaCXX/attr-trivial-abi.cpp index c215f90eb124c..c1f39047f8af8 100644 --- a/clang/test/SemaCXX/attr-trivial-abi.cpp +++ b/clang/test/SemaCXX/attr-trivial-abi.cpp @@ -5,15 +5,7 @@ void __attribute__((trivial_abi)) foo(); // expected-warning {{'trivial_abi' att // Should not crash. template class __attribute__((trivial_abi)) a { a(a &&); }; -#if defined(_WIN64) && !defined(__MINGW32__) -// On Windows/MSVC, to be trivial-for-calls, an object must be trivially copyable. -// (And it is only trivially relocatable, currently, if it is trivial for calls.) -// In this case, it is suppressed by an explicitly defined move constructor. -// Similar concerns apply to later tests that have #if defined(_WIN64) && !defined(__MINGW32__) -static_assert(!__is_trivially_relocatable(a), ""); -#else static_assert(__is_trivially_relocatable(a), ""); -#endif struct [[clang::trivial_abi]] S0 { int a; @@ -39,14 +31,7 @@ struct __attribute__((trivial_abi)) S3_3 { // expected-warning {{'trivial_abi' c S3_3(S3_3 &&); S3_2 s32; }; -#ifdef __ORBIS__ -// The ClangABI4OrPS4 calling convention kind passes classes in registers if the -// copy constructor is trivial for calls *or deleted*, while other platforms do -// not accept deleted constructors. -static_assert(__is_trivially_relocatable(S3_3), ""); -#else static_assert(!__is_trivially_relocatable(S3_3), ""); -#endif // Diagnose invalid trivial_abi even when the type is templated because it has a non-trivial field. template @@ -118,30 +103,18 @@ struct __attribute__((trivial_abi)) CopyMoveDeleted { // expected-warning {{'tri CopyMoveDeleted(const CopyMoveDeleted &) = delete; CopyMoveDeleted(CopyMoveDeleted &&) = delete; }; -#ifdef __ORBIS__ static_assert(__is_trivially_relocatable(CopyMoveDeleted), ""); -#else -static_assert(!__is_trivially_relocatable(CopyMoveDeleted), ""); -#endif 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; }; -#ifdef __ORBIS__ static_assert(__is_trivially_relocatable(S18), ""); -#else -static_assert(!__is_trivially_relocatable(S18), ""); -#endif struct __attribute__((trivial_abi)) CopyDeleted { CopyDeleted(const CopyDeleted &) = delete; CopyDeleted(CopyDeleted &&) = default; }; -#if defined(_WIN64) && !defined(__MINGW32__) -static_assert(!__is_trivially_relocatable(CopyDeleted), ""); -#else static_assert(__is_trivially_relocatable(CopyDeleted), ""); -#endif struct __attribute__((trivial_abi)) MoveDeleted { MoveDeleted(const MoveDeleted &) = default; @@ -153,19 +126,11 @@ struct __attribute__((trivial_abi)) S19 { // expected-warning {{'trivial_abi' ca CopyDeleted a; MoveDeleted b; }; -#ifdef __ORBIS__ static_assert(__is_trivially_relocatable(S19), ""); -#else -static_assert(!__is_trivially_relocatable(S19), ""); -#endif // 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. }; -#if defined(_WIN64) && !defined(__MINGW32__) -static_assert(!__is_trivially_relocatable(S20), ""); -#else static_assert(__is_trivially_relocatable(S20), ""); -#endif } // namespace deletedCopyMoveConstructor diff --git a/clang/test/SemaCXX/is-trivially-relocatable.cpp b/clang/test/SemaCXX/is-trivially-relocatable.cpp new file mode 100644 index 0000000000000..5198bf40d7c82 --- /dev/null +++ b/clang/test/SemaCXX/is-trivially-relocatable.cpp @@ -0,0 +1,206 @@ +// RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s -triple x86_64-windows-msvc +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -triple x86_64-windows-msvc +// RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s -triple x86_64-apple-darwin10 +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -triple x86_64-apple-darwin10 + +// expected-no-diagnostics + +#if __cplusplus < 201103L +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__, "") +// cxx98-error@-1 {{variadic macros are a C99 feature}} +#endif + +template +struct Agg { + T t_; +}; + +template +struct Der : T { +}; + +template +struct Mut { + mutable T t_; +}; + +template +struct Non { + Non(); // make it a non-aggregate + T t_; +}; + +struct CompletelyTrivial { +}; +static_assert(__is_trivially_relocatable(CompletelyTrivial)); +static_assert(__is_trivially_relocatable(Agg)); +static_assert(__is_trivially_relocatable(Der)); +static_assert(__is_trivially_relocatable(Mut)); +static_assert(__is_trivially_relocatable(Non)); + +struct NonTrivialDtor { + ~NonTrivialDtor(); +}; +static_assert(!__is_trivially_relocatable(NonTrivialDtor)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); + +struct NonTrivialCopyCtor { + NonTrivialCopyCtor(const NonTrivialCopyCtor&); +}; +static_assert(!__is_trivially_relocatable(NonTrivialCopyCtor)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); + +struct NonTrivialMutableCopyCtor { + NonTrivialMutableCopyCtor(NonTrivialMutableCopyCtor&); +}; +static_assert(!__is_trivially_relocatable(NonTrivialMutableCopyCtor)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); + +#if __cplusplus >= 201103L +struct NonTrivialMoveCtor { + NonTrivialMoveCtor(NonTrivialMoveCtor&&); +}; +static_assert(!__is_trivially_relocatable(NonTrivialMoveCtor)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); +#endif + +struct NonTrivialCopyAssign { + NonTrivialCopyAssign& operator=(const NonTrivialCopyAssign&); +}; +static_assert(!__is_trivially_relocatable(NonTrivialCopyAssign)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); + +struct NonTrivialMutableCopyAssign { + NonTrivialMutableCopyAssign& operator=(NonTrivialMutableCopyAssign&); +}; +static_assert(!__is_trivially_relocatable(NonTrivialMutableCopyAssign)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); + +#if __cplusplus >= 201103L +struct NonTrivialMoveAssign { + NonTrivialMoveAssign& operator=(NonTrivialMoveAssign&&); +}; +static_assert(!__is_trivially_relocatable(NonTrivialMoveAssign)); +static_assert(!__is_trivially_relocatable(Agg)); +static_assert(!__is_trivially_relocatable(Der)); +static_assert(!__is_trivially_relocatable(Mut)); +static_assert(!__is_trivially_relocatable(Non)); +#endif + +#if __cplusplus >= 202002L +template +struct EligibleNonTrivialDefaultCtor { + EligibleNonTrivialDefaultCtor() requires B; + EligibleNonTrivialDefaultCtor() = default; +}; +// Only the Rule of 5 members (not default ctor) affect trivial relocatability. +static_assert(__is_trivially_relocatable(EligibleNonTrivialDefaultCtor)); +static_assert(__is_trivially_relocatable(EligibleNonTrivialDefaultCtor)); + +template +struct IneligibleNonTrivialDefaultCtor { + IneligibleNonTrivialDefaultCtor(); + IneligibleNonTrivialDefaultCtor() requires B = default; +}; +// Only the Rule of 5 members (not default ctor) affect trivial relocatability. +static_assert(__is_trivially_relocatable(IneligibleNonTrivialDefaultCtor)); +static_assert(__is_trivially_relocatable(IneligibleNonTrivialDefaultCtor)); + +template +struct EligibleNonTrivialCopyCtor { + EligibleNonTrivialCopyCtor(const EligibleNonTrivialCopyCtor&) requires B; + EligibleNonTrivialCopyCtor(const EligibleNonTrivialCopyCtor&) = default; +}; +static_assert(!__is_trivially_relocatable(EligibleNonTrivialCopyCtor)); +static_assert(__is_trivially_relocatable(EligibleNonTrivialCopyCtor)); + +template +struct IneligibleNonTrivialCopyCtor { + IneligibleNonTrivialCopyCtor(const IneligibleNonTrivialCopyCtor&); + IneligibleNonTrivialCopyCtor(const IneligibleNonTrivialCopyCtor&) requires B = default; +}; +static_assert(__is_trivially_relocatable(IneligibleNonTrivialCopyCtor)); +static_assert(!__is_trivially_relocatable(IneligibleNonTrivialCopyCtor)); + +template +struct EligibleNonTrivialMoveCtor { + EligibleNonTrivialMoveCtor(EligibleNonTrivialMoveCtor&&) requires B; + EligibleNonTrivialMoveCtor(EligibleNonTrivialMoveCtor&&) = default; +}; +static_assert(!__is_trivially_relocatable(EligibleNonTrivialMoveCtor)); +static_assert(__is_trivially_relocatable(EligibleNonTrivialMoveCtor)); + +template +struct IneligibleNonTrivialMoveCtor { + IneligibleNonTrivialMoveCtor(IneligibleNonTrivialMoveCtor&&); + IneligibleNonTrivialMoveCtor(IneligibleNonTrivialMoveCtor&&) requires B = default; +}; +static_assert(__is_trivially_relocatable(IneligibleNonTrivialMoveCtor)); +static_assert(!__is_trivially_relocatable(IneligibleNonTrivialMoveCtor)); + +template +struct EligibleNonTrivialCopyAssign { + EligibleNonTrivialCopyAssign& operator=(const EligibleNonTrivialCopyAssign&) requires B; + EligibleNonTrivialCopyAssign& operator=(const EligibleNonTrivialCopyAssign&) = default; +}; +static_assert(!__is_trivially_relocatable(EligibleNonTrivialCopyAssign)); +static_assert(__is_trivially_relocatable(EligibleNonTrivialCopyAssign)); + +template +struct IneligibleNonTrivialCopyAssign { + IneligibleNonTrivialCopyAssign& operator=(const IneligibleNonTrivialCopyAssign&); + IneligibleNonTrivialCopyAssign& operator=(const IneligibleNonTrivialCopyAssign&) requires B = default; +}; +static_assert(__is_trivially_relocatable(IneligibleNonTrivialCopyAssign)); +static_assert(!__is_trivially_relocatable(IneligibleNonTrivialCopyAssign)); + +template +struct EligibleNonTrivialMoveAssign { + EligibleNonTrivialMoveAssign& operator=(EligibleNonTrivialMoveAssign&&) requires B; + EligibleNonTrivialMoveAssign& operator=(EligibleNonTrivialMoveAssign&&) = default; +}; +static_assert(!__is_trivially_relocatable(EligibleNonTrivialMoveAssign)); +static_assert(__is_trivially_relocatable(EligibleNonTrivialMoveAssign)); + +template +struct IneligibleNonTrivialMoveAssign { + IneligibleNonTrivialMoveAssign& operator=(IneligibleNonTrivialMoveAssign&&); + IneligibleNonTrivialMoveAssign& operator=(IneligibleNonTrivialMoveAssign&&) requires B = default; +}; +static_assert(__is_trivially_relocatable(IneligibleNonTrivialMoveAssign)); +static_assert(!__is_trivially_relocatable(IneligibleNonTrivialMoveAssign)); + +template +struct EligibleNonTrivialDtor { + ~EligibleNonTrivialDtor() requires B; + ~EligibleNonTrivialDtor() = default; +}; +static_assert(!__is_trivially_relocatable(EligibleNonTrivialDtor)); +static_assert(__is_trivially_relocatable(EligibleNonTrivialDtor)); + +template +struct IneligibleNonTrivialDtor { + ~IneligibleNonTrivialDtor(); + ~IneligibleNonTrivialDtor() requires B = default; +}; +static_assert(__is_trivially_relocatable(IneligibleNonTrivialDtor)); +static_assert(!__is_trivially_relocatable(IneligibleNonTrivialDtor)); +#endif diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 14ec17989ec7c..4f9c771944614 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -3342,14 +3342,34 @@ static_assert(__is_trivially_relocatable(int)); static_assert(__is_trivially_relocatable(int[])); static_assert(__is_trivially_relocatable(const int)); static_assert(__is_trivially_relocatable(volatile int)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(!__is_trivially_relocatable(int&)); +static_assert(!__is_trivially_relocatable(const int&)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); + +static_assert(!__is_trivially_relocatable(Polymorph)); +static_assert(!__is_trivially_relocatable(InheritPolymorph)); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); + +static_assert(__is_trivially_relocatable(HasPrivateBase)); +static_assert(__is_trivially_relocatable(HasProtectedBase)); +static_assert(!__is_trivially_relocatable(HasVirtBase)); enum Enum {}; static_assert(__is_trivially_relocatable(Enum)); static_assert(__is_trivially_relocatable(Enum[])); +static_assert(__is_trivially_relocatable(AggregateTemplate)); union Union {int x;}; static_assert(__is_trivially_relocatable(Union)); static_assert(__is_trivially_relocatable(Union[])); +static_assert(__is_trivially_relocatable(AggregateTemplate)); struct Trivial {}; static_assert(__is_trivially_relocatable(Trivial)); @@ -3359,6 +3379,7 @@ static_assert(__is_trivially_relocatable(volatile Trivial)); static_assert(__is_trivially_relocatable(Trivial[])); static_assert(__is_trivially_relocatable(const Trivial[])); static_assert(__is_trivially_relocatable(volatile Trivial[])); +static_assert(__is_trivially_relocatable(AggregateTemplate)); static_assert(__is_trivially_relocatable(int[10])); static_assert(__is_trivially_relocatable(const int[10])); @@ -3386,18 +3407,21 @@ static_assert(!__is_trivially_relocatable(NontrivialDtor)); static_assert(!__is_trivially_relocatable(NontrivialDtor[])); static_assert(!__is_trivially_relocatable(const NontrivialDtor)); static_assert(!__is_trivially_relocatable(volatile NontrivialDtor)); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); struct NontrivialCopyCtor { NontrivialCopyCtor(const NontrivialCopyCtor&) {} }; static_assert(!__is_trivially_relocatable(NontrivialCopyCtor)); static_assert(!__is_trivially_relocatable(NontrivialCopyCtor[])); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); struct NontrivialMoveCtor { NontrivialMoveCtor(NontrivialMoveCtor&&) {} }; static_assert(!__is_trivially_relocatable(NontrivialMoveCtor)); static_assert(!__is_trivially_relocatable(NontrivialMoveCtor[])); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); struct [[clang::trivial_abi]] TrivialAbiNontrivialDtor { ~TrivialAbiNontrivialDtor() {} @@ -3406,6 +3430,8 @@ static_assert(__is_trivially_relocatable(TrivialAbiNontrivialDtor)); static_assert(__is_trivially_relocatable(TrivialAbiNontrivialDtor[])); static_assert(__is_trivially_relocatable(const TrivialAbiNontrivialDtor)); static_assert(__is_trivially_relocatable(volatile TrivialAbiNontrivialDtor)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(NonAggregateTemplate)); struct [[clang::trivial_abi]] TrivialAbiNontrivialCopyCtor { TrivialAbiNontrivialCopyCtor(const TrivialAbiNontrivialCopyCtor&) {} @@ -3414,6 +3440,8 @@ static_assert(__is_trivially_relocatable(TrivialAbiNontrivialCopyCtor)); static_assert(__is_trivially_relocatable(TrivialAbiNontrivialCopyCtor[])); static_assert(__is_trivially_relocatable(const TrivialAbiNontrivialCopyCtor)); static_assert(__is_trivially_relocatable(volatile TrivialAbiNontrivialCopyCtor)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(NonAggregateTemplate)); // A more complete set of tests for the behavior of trivial_abi can be found in // clang/test/SemaCXX/attr-trivial-abi.cpp @@ -3424,6 +3452,34 @@ static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor)); static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor[])); static_assert(__is_trivially_relocatable(const TrivialAbiNontrivialMoveCtor)); static_assert(__is_trivially_relocatable(volatile TrivialAbiNontrivialMoveCtor)); +static_assert(__is_trivially_relocatable(AggregateTemplate)); +static_assert(__is_trivially_relocatable(NonAggregateTemplate)); + +struct NontrivialNonConstCopyConstructor { + NontrivialNonConstCopyConstructor(); + NontrivialNonConstCopyConstructor(NontrivialNonConstCopyConstructor&); + NontrivialNonConstCopyConstructor(const NontrivialNonConstCopyConstructor&) = default; + NontrivialNonConstCopyConstructor& operator=(const NontrivialNonConstCopyConstructor&) = default; + ~NontrivialNonConstCopyConstructor() = default; +}; +static_assert(!__is_trivially_relocatable(NontrivialNonConstCopyConstructor)); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); + +struct NontrivialCopyAssignment { + NontrivialCopyAssignment(const NontrivialCopyAssignment&) = default; + NontrivialCopyAssignment& operator=(const NontrivialCopyAssignment&); + ~NontrivialCopyAssignment() = default; +}; +static_assert(!__is_trivially_relocatable(NontrivialCopyAssignment)); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); + +struct NontrivialMoveAssignment { + NontrivialMoveAssignment(NontrivialMoveAssignment&&) = default; + NontrivialMoveAssignment& operator=(NontrivialMoveAssignment&&); + ~NontrivialMoveAssignment() = default; +}; +static_assert(!__is_trivially_relocatable(NontrivialMoveAssignment)); +static_assert(!__is_trivially_relocatable(AggregateTemplate)); } // namespace is_trivially_relocatable