203 lines
8.9 KiB
C++
203 lines
8.9 KiB
C++
|
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||
|
|
||
|
// expected-no-diagnostics
|
||
|
|
||
|
template<typename T, bool B> struct trivially_assignable_check {
|
||
|
static_assert(B == __has_trivial_assign(T), "");
|
||
|
static_assert(B == __is_trivially_assignable(T&, T), "");
|
||
|
static_assert(B == __is_trivially_assignable(T&, const T &), "");
|
||
|
static_assert(B == __is_trivially_assignable(T&, T &&), "");
|
||
|
static_assert(B == __is_trivially_assignable(T&&, T), "");
|
||
|
static_assert(B == __is_trivially_assignable(T&&, const T &), "");
|
||
|
static_assert(B == __is_trivially_assignable(T&&, T &&), "");
|
||
|
typedef void type;
|
||
|
};
|
||
|
template<typename T> using trivially_assignable =
|
||
|
typename trivially_assignable_check<T, true>::type;
|
||
|
template<typename T> using not_trivially_assignable =
|
||
|
typename trivially_assignable_check<T, false>::type;
|
||
|
|
||
|
struct Trivial {};
|
||
|
using _ = trivially_assignable<Trivial>;
|
||
|
|
||
|
// A copy/move assignment operator for class X is trivial if it is not user-provided,
|
||
|
struct UserProvided {
|
||
|
UserProvided &operator=(const UserProvided &);
|
||
|
};
|
||
|
using _ = not_trivially_assignable<UserProvided>;
|
||
|
|
||
|
// its declared parameter type is the same as if it had been implicitly
|
||
|
// declared,
|
||
|
struct NonConstCopy {
|
||
|
NonConstCopy &operator=(NonConstCopy &) = default;
|
||
|
};
|
||
|
using _ = not_trivially_assignable<NonConstCopy>;
|
||
|
|
||
|
// class X has no virtual functions
|
||
|
struct VFn {
|
||
|
virtual void f();
|
||
|
};
|
||
|
using _ = not_trivially_assignable<VFn>;
|
||
|
|
||
|
// and no virtual base classes
|
||
|
struct VBase : virtual Trivial {};
|
||
|
using _ = not_trivially_assignable<VBase>;
|
||
|
|
||
|
// and the assignment operator selected to copy/move each [direct subobject] is trivial
|
||
|
struct TemplateCtor {
|
||
|
template<typename T> TemplateCtor operator=(T &);
|
||
|
};
|
||
|
using _ = trivially_assignable<TemplateCtor>;
|
||
|
struct TemplateCtorMember {
|
||
|
TemplateCtor tc;
|
||
|
};
|
||
|
using _ = trivially_assignable<TemplateCtorMember>;
|
||
|
struct MutableTemplateCtorMember {
|
||
|
mutable TemplateCtor mtc;
|
||
|
};
|
||
|
static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
|
||
|
static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
|
||
|
|
||
|
// Both trivial and non-trivial special members.
|
||
|
struct TNT {
|
||
|
TNT &operator=(const TNT &) = default; // trivial
|
||
|
TNT &operator=(TNT &); // non-trivial
|
||
|
|
||
|
TNT &operator=(TNT &&) = default; // trivial
|
||
|
TNT &operator=(const TNT &&); // non-trivial
|
||
|
};
|
||
|
|
||
|
static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility");
|
||
|
static_assert(__is_trivially_assignable(TNT, TNT), "");
|
||
|
static_assert(!__is_trivially_assignable(TNT, TNT &), "");
|
||
|
static_assert(__is_trivially_assignable(TNT, const TNT &), "");
|
||
|
static_assert(!__is_trivially_assignable(TNT, volatile TNT &), "");
|
||
|
static_assert(__is_trivially_assignable(TNT, TNT &&), "");
|
||
|
static_assert(!__is_trivially_assignable(TNT, const TNT &&), "");
|
||
|
static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), "");
|
||
|
|
||
|
// This has only trivial special members.
|
||
|
struct DerivedFromTNT : TNT {};
|
||
|
|
||
|
static_assert(__has_trivial_assign(DerivedFromTNT), "");
|
||
|
static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), "");
|
||
|
static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), "");
|
||
|
static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), "");
|
||
|
static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), "");
|
||
|
static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), "");
|
||
|
static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), "");
|
||
|
static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), "");
|
||
|
|
||
|
// This has only trivial special members.
|
||
|
struct TNTMember {
|
||
|
TNT tnt;
|
||
|
};
|
||
|
|
||
|
static_assert(__has_trivial_assign(TNTMember), "");
|
||
|
static_assert(__is_trivially_assignable(TNTMember, TNTMember), "");
|
||
|
static_assert(__is_trivially_assignable(TNTMember, TNTMember &), "");
|
||
|
static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), "");
|
||
|
static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), "");
|
||
|
static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), "");
|
||
|
static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), "");
|
||
|
static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), "");
|
||
|
|
||
|
struct NCCTNT : NonConstCopy, TNT {};
|
||
|
|
||
|
static_assert(!__has_trivial_assign(NCCTNT), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), "");
|
||
|
static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), "");
|
||
|
|
||
|
struct MultipleTrivial {
|
||
|
// All four of these are trivial.
|
||
|
MultipleTrivial &operator=(const MultipleTrivial &) & = default;
|
||
|
MultipleTrivial &operator=(const MultipleTrivial &) && = default;
|
||
|
MultipleTrivial &operator=(MultipleTrivial &&) & = default;
|
||
|
MultipleTrivial &operator=(MultipleTrivial &&) && = default;
|
||
|
};
|
||
|
|
||
|
using _ = trivially_assignable<MultipleTrivial>;
|
||
|
|
||
|
struct RefQualifier {
|
||
|
RefQualifier &operator=(const RefQualifier &) & = default;
|
||
|
RefQualifier &operator=(const RefQualifier &) &&;
|
||
|
RefQualifier &operator=(RefQualifier &&) &;
|
||
|
RefQualifier &operator=(RefQualifier &&) && = default;
|
||
|
};
|
||
|
struct DerivedFromRefQualifier : RefQualifier {
|
||
|
// Both of these call the trivial copy operation.
|
||
|
DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default;
|
||
|
DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default;
|
||
|
// Both of these call the non-trivial move operation.
|
||
|
DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default;
|
||
|
DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default;
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), "");
|
||
|
static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");
|
||
|
static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");
|
||
|
static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");
|
||
|
|
||
|
struct TemplateAssignNoMove {
|
||
|
TemplateAssignNoMove &operator=(const TemplateAssignNoMove &) = default;
|
||
|
template<typename T> TemplateAssignNoMove &operator=(T &&);
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(TemplateAssignNoMove, const TemplateAssignNoMove &), "");
|
||
|
static_assert(!__is_trivially_assignable(TemplateAssignNoMove, TemplateAssignNoMove &&), "");
|
||
|
|
||
|
struct UseTemplateAssignNoMove {
|
||
|
TemplateAssignNoMove tanm;
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(UseTemplateAssignNoMove, const UseTemplateAssignNoMove &), "");
|
||
|
static_assert(!__is_trivially_assignable(UseTemplateAssignNoMove, UseTemplateAssignNoMove &&), "");
|
||
|
|
||
|
struct TemplateAssignNoMoveSFINAE {
|
||
|
TemplateAssignNoMoveSFINAE &operator=(const TemplateAssignNoMoveSFINAE &) = default;
|
||
|
template<typename T, typename U = typename T::error> TemplateAssignNoMoveSFINAE &operator=(T &&);
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, const TemplateAssignNoMoveSFINAE &), "");
|
||
|
static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, TemplateAssignNoMoveSFINAE &&), "");
|
||
|
|
||
|
struct UseTemplateAssignNoMoveSFINAE {
|
||
|
TemplateAssignNoMoveSFINAE tanm;
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, const UseTemplateAssignNoMoveSFINAE &), "");
|
||
|
static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, UseTemplateAssignNoMoveSFINAE &&), "");
|
||
|
|
||
|
namespace TrivialityDependsOnImplicitDeletion {
|
||
|
struct PrivateMove {
|
||
|
PrivateMove &operator=(const PrivateMove &) = default;
|
||
|
private:
|
||
|
PrivateMove &operator=(PrivateMove &&);
|
||
|
friend class Access;
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(PrivateMove, const PrivateMove &), "");
|
||
|
static_assert(!__is_trivially_assignable(PrivateMove, PrivateMove &&), "");
|
||
|
|
||
|
struct NoAccess {
|
||
|
PrivateMove pm;
|
||
|
// NoAccess's move would be deleted, so is suppressed,
|
||
|
// so moves of it use PrivateMove's copy ctor, which is trivial.
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(NoAccess, const NoAccess &), "");
|
||
|
static_assert(__is_trivially_assignable(NoAccess, NoAccess &&), "");
|
||
|
struct TopNoAccess : NoAccess {};
|
||
|
static_assert(__is_trivially_assignable(TopNoAccess, const TopNoAccess &), "");
|
||
|
static_assert(__is_trivially_assignable(TopNoAccess, TopNoAccess &&), "");
|
||
|
|
||
|
struct Access {
|
||
|
PrivateMove pm;
|
||
|
// NoAccess's move would *not* be deleted, so is *not* suppressed,
|
||
|
// so moves of it use PrivateMove's move ctor, which is not trivial.
|
||
|
};
|
||
|
static_assert(__is_trivially_assignable(Access, const Access &), "");
|
||
|
static_assert(!__is_trivially_assignable(Access, Access &&), "");
|
||
|
struct TopAccess : Access {};
|
||
|
static_assert(__is_trivially_assignable(TopAccess, const TopAccess &), "");
|
||
|
static_assert(!__is_trivially_assignable(TopAccess, TopAccess &&), "");
|
||
|
}
|