255 lines · cpp
1// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-builtins2// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-builtins -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=143// RUN: %clang_cc1 -fsyntax-only -std=c++2b -DDEDUCING_THIS -Wno-deprecated-builtins %s -verify4 5// expected-no-diagnostics6 7#if DEDUCING_THIS8#define EXPLICIT_PARAMETER(...) this __VA_ARGS__,9#else10#define EXPLICIT_PARAMETER(Param)11#endif12 13 14template<typename T, bool B> struct trivially_assignable_check {15 static_assert(B == __has_trivial_assign(T), "");16 static_assert(B == __is_trivially_assignable(T&, T), "");17 static_assert(B == __is_trivially_assignable(T&, const T &), "");18 static_assert(B == __is_trivially_assignable(T&, T &&), "");19 static_assert(B == __is_trivially_assignable(T&&, T), "");20 static_assert(B == __is_trivially_assignable(T&&, const T &), "");21 static_assert(B == __is_trivially_assignable(T&&, T &&), "");22 typedef void type;23};24template<typename T> using trivially_assignable =25 typename trivially_assignable_check<T, true>::type;26template<typename T> using not_trivially_assignable =27 typename trivially_assignable_check<T, false>::type;28 29struct Trivial {};30using _ = trivially_assignable<Trivial>;31 32// A copy/move assignment operator for class X is trivial if it is not user-provided,33struct UserProvided {34 UserProvided &operator=(EXPLICIT_PARAMETER(UserProvided&)35 const UserProvided &);36};37using _ = not_trivially_assignable<UserProvided>;38 39// its declared parameter type is the same as if it had been implicitly40// declared,41struct NonConstCopy {42 NonConstCopy &operator=(EXPLICIT_PARAMETER(NonConstCopy&) NonConstCopy &) = default;43#if DEDUCING_THIS44 NonConstCopy &operator=(EXPLICIT_PARAMETER(NonConstCopy&&) NonConstCopy &) = default;45#endif46};47#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 1448// Up until (and including) Clang 14, non-const copy assignment operators were not trivial because49// of dr217150using _ = not_trivially_assignable<NonConstCopy>;51#else52// In the latest Clang version, all defaulted assignment operators are trivial, even if non-const,53// because dr2171 is fixed54static_assert(__has_trivial_assign(NonConstCopy), "");55static_assert(__is_trivially_assignable(NonConstCopy &, NonConstCopy &), "");56static_assert(!__is_trivially_assignable(NonConstCopy &, const NonConstCopy &), "");57static_assert(!__is_trivially_assignable(NonConstCopy &, NonConstCopy), "");58static_assert(!__is_trivially_assignable(NonConstCopy &, NonConstCopy &&), "");59static_assert(__is_trivially_assignable(NonConstCopy &&, NonConstCopy &), "");60static_assert(!__is_trivially_assignable(NonConstCopy &&, const NonConstCopy &), "");61static_assert(!__is_trivially_assignable(NonConstCopy &&, NonConstCopy), "");62static_assert(!__is_trivially_assignable(NonConstCopy &&, NonConstCopy &&), "");63 64struct DefaultedSpecialMembers {65 DefaultedSpecialMembers &operator=(EXPLICIT_PARAMETER(DefaultedSpecialMembers&)66 const DefaultedSpecialMembers &) = default;67 DefaultedSpecialMembers &operator=(EXPLICIT_PARAMETER(DefaultedSpecialMembers&)68 DefaultedSpecialMembers &) = default;69 DefaultedSpecialMembers &operator=(EXPLICIT_PARAMETER(DefaultedSpecialMembers&)70 DefaultedSpecialMembers &&) = default;71#if DEDUCING_THIS72 DefaultedSpecialMembers &operator=(EXPLICIT_PARAMETER(DefaultedSpecialMembers&&)73 const DefaultedSpecialMembers &) = default;74 DefaultedSpecialMembers &operator=(EXPLICIT_PARAMETER(DefaultedSpecialMembers&&)75 DefaultedSpecialMembers &) = default;76 DefaultedSpecialMembers &operator=(EXPLICIT_PARAMETER(DefaultedSpecialMembers&&)77 DefaultedSpecialMembers &&) = default;78#endif79};80using _ = trivially_assignable<DefaultedSpecialMembers>;81#endif82 83// class X has no virtual functions84struct VFn {85 virtual void f();86};87using _ = not_trivially_assignable<VFn>;88 89// and no virtual base classes90struct VBase : virtual Trivial {};91using _ = not_trivially_assignable<VBase>;92 93// and the assignment operator selected to copy/move each [direct subobject] is trivial94struct TemplateCtor {95 template<typename T> TemplateCtor operator=(T &);96};97using _ = trivially_assignable<TemplateCtor>;98struct TemplateCtorMember {99 TemplateCtor tc;100};101using _ = trivially_assignable<TemplateCtorMember>;102struct MutableTemplateCtorMember {103 mutable TemplateCtor mtc;104};105static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");106static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");107 108// Both trivial and non-trivial special members.109struct TNT {110 TNT &operator=(EXPLICIT_PARAMETER(TNT&) const TNT &) = default; // trivial111 TNT &operator=(EXPLICIT_PARAMETER(TNT&) TNT &); // non-trivial112 TNT &operator=(EXPLICIT_PARAMETER(TNT&) TNT &&) = default; // trivial113 TNT &operator=(EXPLICIT_PARAMETER(TNT&) const TNT &&); // non-trivial114#if DEDUCING_THIS115 TNT &operator=(this TNT&&, const TNT &) = default; // trivial116 TNT &operator=(this TNT&&, TNT &); // non-trivial117 TNT &operator=(this TNT&&, TNT &&) = default; // trivial118 TNT &operator=(this TNT&&, const TNT &&); // non-trivial119#endif120};121 122static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility");123static_assert(__is_trivially_assignable(TNT, TNT), "");124static_assert(!__is_trivially_assignable(TNT, TNT &), "");125static_assert(__is_trivially_assignable(TNT, const TNT &), "");126static_assert(!__is_trivially_assignable(TNT, volatile TNT &), "");127static_assert(__is_trivially_assignable(TNT, TNT &&), "");128static_assert(!__is_trivially_assignable(TNT, const TNT &&), "");129static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), "");130 131// This has only trivial special members.132struct DerivedFromTNT : TNT {};133 134static_assert(__has_trivial_assign(DerivedFromTNT), "");135static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), "");136static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), "");137static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), "");138static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), "");139static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), "");140static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), "");141static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), "");142 143// This has only trivial special members.144struct TNTMember {145 TNT tnt;146};147 148static_assert(__has_trivial_assign(TNTMember), "");149static_assert(__is_trivially_assignable(TNTMember, TNTMember), "");150static_assert(__is_trivially_assignable(TNTMember, TNTMember &), "");151static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), "");152static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), "");153static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), "");154static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), "");155static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), "");156 157struct NCCTNT : NonConstCopy, TNT {};158 159static_assert(!__has_trivial_assign(NCCTNT), "");160static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), "");161static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), "");162static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), "");163static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), "");164static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), "");165static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), "");166static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), "");167 168struct MultipleTrivial {169 // All four of these are trivial.170 MultipleTrivial &operator=(const MultipleTrivial &) & = default;171 MultipleTrivial &operator=(const MultipleTrivial &) && = default;172 MultipleTrivial &operator=(MultipleTrivial &&) & = default;173 MultipleTrivial &operator=(MultipleTrivial &&) && = default;174};175 176using _ = trivially_assignable<MultipleTrivial>;177 178struct RefQualifier {179 RefQualifier &operator=(const RefQualifier &) & = default;180 RefQualifier &operator=(const RefQualifier &) &&;181 RefQualifier &operator=(RefQualifier &&) &;182 RefQualifier &operator=(RefQualifier &&) && = default;183};184struct DerivedFromRefQualifier : RefQualifier {185 // Both of these call the trivial copy operation.186 DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default;187 DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default;188 // Both of these call the non-trivial move operation.189 DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default;190 DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default;191};192static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), "");193static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");194static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");195static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");196 197struct TemplateAssignNoMove {198 TemplateAssignNoMove &operator=(const TemplateAssignNoMove &) = default;199 template<typename T> TemplateAssignNoMove &operator=(T &&);200};201static_assert(__is_trivially_assignable(TemplateAssignNoMove, const TemplateAssignNoMove &), "");202static_assert(!__is_trivially_assignable(TemplateAssignNoMove, TemplateAssignNoMove &&), "");203 204struct UseTemplateAssignNoMove {205 TemplateAssignNoMove tanm;206};207static_assert(__is_trivially_assignable(UseTemplateAssignNoMove, const UseTemplateAssignNoMove &), "");208static_assert(!__is_trivially_assignable(UseTemplateAssignNoMove, UseTemplateAssignNoMove &&), "");209 210struct TemplateAssignNoMoveSFINAE {211 TemplateAssignNoMoveSFINAE &operator=(const TemplateAssignNoMoveSFINAE &) = default;212 template<typename T, typename U = typename T::error> TemplateAssignNoMoveSFINAE &operator=(T &&);213};214static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, const TemplateAssignNoMoveSFINAE &), "");215static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, TemplateAssignNoMoveSFINAE &&), "");216 217struct UseTemplateAssignNoMoveSFINAE {218 TemplateAssignNoMoveSFINAE tanm;219};220static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, const UseTemplateAssignNoMoveSFINAE &), "");221static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, UseTemplateAssignNoMoveSFINAE &&), "");222 223namespace TrivialityDependsOnImplicitDeletion {224 struct PrivateMove {225 PrivateMove &operator=(const PrivateMove &) = default;226 private:227 PrivateMove &operator=(PrivateMove &&);228 friend class Access;229 };230 static_assert(__is_trivially_assignable(PrivateMove, const PrivateMove &), "");231 static_assert(!__is_trivially_assignable(PrivateMove, PrivateMove &&), "");232 233 struct NoAccess {234 PrivateMove pm;235 // NoAccess's move would be deleted, so is suppressed,236 // so moves of it use PrivateMove's copy ctor, which is trivial.237 };238 static_assert(__is_trivially_assignable(NoAccess, const NoAccess &), "");239 static_assert(__is_trivially_assignable(NoAccess, NoAccess &&), "");240 struct TopNoAccess : NoAccess {};241 static_assert(__is_trivially_assignable(TopNoAccess, const TopNoAccess &), "");242 static_assert(__is_trivially_assignable(TopNoAccess, TopNoAccess &&), "");243 244 struct Access {245 PrivateMove pm;246 // NoAccess's move would *not* be deleted, so is *not* suppressed,247 // so moves of it use PrivateMove's move ctor, which is not trivial.248 };249 static_assert(__is_trivially_assignable(Access, const Access &), "");250 static_assert(!__is_trivially_assignable(Access, Access &&), "");251 struct TopAccess : Access {};252 static_assert(__is_trivially_assignable(TopAccess, const TopAccess &), "");253 static_assert(!__is_trivially_assignable(TopAccess, TopAccess &&), "");254}255