diff options
Diffstat (limited to 'test/CXX/special/class.copy')
-rw-r--r-- | test/CXX/special/class.copy/implicit-move.cpp | 2 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p12-0x.cpp | 216 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p18-cxx11.cpp | 62 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p23-cxx11.cpp | 2 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p25-0x.cpp | 202 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p28-cxx11.cpp | 19 |
6 files changed, 501 insertions, 2 deletions
diff --git a/test/CXX/special/class.copy/implicit-move.cpp b/test/CXX/special/class.copy/implicit-move.cpp index 597e327..3337412 100644 --- a/test/CXX/special/class.copy/implicit-move.cpp +++ b/test/CXX/special/class.copy/implicit-move.cpp @@ -54,7 +54,7 @@ void test_basic_exclusion() { static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), ""); HasMoveConstructor hmc; - hmc = HasMoveConstructor(); // expected-error {{selected implicitly-deleted copy assignment}} + hmc = HasMoveConstructor(); // expected-error {{object of type 'HasMoveConstructor' cannot be assigned because its copy assignment operator is implicitly deleted}} (HasMoveAssignment(HasMoveAssignment())); // expected-error {{uses deleted function}} HasMoveAssignment hma; diff --git a/test/CXX/special/class.copy/p12-0x.cpp b/test/CXX/special/class.copy/p12-0x.cpp new file mode 100644 index 0000000..17b3191 --- /dev/null +++ b/test/CXX/special/class.copy/p12-0x.cpp @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +// expected-no-diagnostics + +template<typename T, bool B> struct trivially_copyable_check { + static_assert(B == __has_trivial_copy(T), ""); + static_assert(B == __is_trivially_constructible(T, T), ""); + static_assert(B == __is_trivially_constructible(T, const T &), ""); + static_assert(B == __is_trivially_constructible(T, T &&), ""); + typedef void type; +}; +template<typename T> using trivially_copyable = + typename trivially_copyable_check<T, true>::type; +template<typename T> using not_trivially_copyable = + typename trivially_copyable_check<T, false>::type; + +struct Trivial {}; +using _ = trivially_copyable<Trivial>; + +// A copy/move constructor for class X is trivial if it is not user-provided, +struct UserProvided { + UserProvided(const UserProvided &); +}; +using _ = not_trivially_copyable<UserProvided>; + +// its declared parameter type is the same as if it had been implicitly +// declared, +struct NonConstCopy { + NonConstCopy(NonConstCopy &) = default; +}; +using _ = not_trivially_copyable<NonConstCopy>; + +// class X has no virtual functions +struct VFn { + virtual void f(); +}; +using _ = not_trivially_copyable<VFn>; + +// and no virtual base classes +struct VBase : virtual Trivial {}; +using _ = not_trivially_copyable<VBase>; + +// and the constructor selected to copy/move each [direct subobject] is trivial +struct TemplateCtor { + template<typename T> TemplateCtor(T &); +}; +using _ = trivially_copyable<TemplateCtor>; +struct TemplateCtorMember { + TemplateCtor tc; +}; +using _ = trivially_copyable<TemplateCtorMember>; + +// We can select a non-trivial copy ctor even if there is a trivial one. +struct MutableTemplateCtorMember { + mutable TemplateCtor mtc; +}; +static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); +static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), ""); +struct MutableTemplateCtorMember2 { + MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default; + MutableTemplateCtorMember2(MutableTemplateCtorMember2 &&) = default; + mutable TemplateCtor mtc; +}; +static_assert(!__is_trivially_constructible(MutableTemplateCtorMember2, const MutableTemplateCtorMember2 &), ""); +static_assert(__is_trivially_constructible(MutableTemplateCtorMember2, MutableTemplateCtorMember2 &&), ""); + +// Both trivial and non-trivial special members. +struct TNT { + TNT(const TNT &) = default; // trivial + TNT(TNT &); // non-trivial + + TNT(TNT &&) = default; // trivial + TNT(const TNT &&); // non-trivial +}; + +static_assert(!__has_trivial_copy(TNT), "lie deliberately for gcc compatibility"); +static_assert(__is_trivially_constructible(TNT, TNT), ""); +static_assert(!__is_trivially_constructible(TNT, TNT &), ""); +static_assert(__is_trivially_constructible(TNT, const TNT &), ""); +static_assert(!__is_trivially_constructible(TNT, volatile TNT &), ""); +static_assert(__is_trivially_constructible(TNT, TNT &&), ""); +static_assert(!__is_trivially_constructible(TNT, const TNT &&), ""); +static_assert(!__is_trivially_constructible(TNT, volatile TNT &&), ""); + +// This has only trivial special members. +struct DerivedFromTNT : TNT {}; + +static_assert(__has_trivial_copy(DerivedFromTNT), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &), ""); +static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &&), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &&), ""); +static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &&), ""); + +// This has only trivial special members. +struct TNTMember { + TNT tnt; +}; + +static_assert(__has_trivial_copy(TNTMember), ""); +static_assert(__is_trivially_constructible(TNTMember, TNTMember), ""); +static_assert(__is_trivially_constructible(TNTMember, TNTMember &), ""); +static_assert(__is_trivially_constructible(TNTMember, const TNTMember &), ""); +static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &), ""); +static_assert(__is_trivially_constructible(TNTMember, TNTMember &&), ""); +static_assert(__is_trivially_constructible(TNTMember, const TNTMember &&), ""); +static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &&), ""); + +struct NCCTNT : NonConstCopy, TNT {}; + +static_assert(!__has_trivial_copy(NCCTNT), ""); +static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT), ""); +static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &), ""); +static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &), ""); +static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), ""); +static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), ""); +static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), ""); +static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), ""); + +struct TemplateCtorNoMove { + TemplateCtorNoMove(const TemplateCtorNoMove &) = default; + template<typename T> TemplateCtorNoMove(T &&); +}; +static_assert(__is_trivially_constructible(TemplateCtorNoMove, const TemplateCtorNoMove &), ""); +static_assert(!__is_trivially_constructible(TemplateCtorNoMove, TemplateCtorNoMove &&), ""); + +struct UseTemplateCtorNoMove { + TemplateCtorNoMove tcnm; +}; +static_assert(__is_trivially_constructible(UseTemplateCtorNoMove, const UseTemplateCtorNoMove &), ""); +static_assert(!__is_trivially_constructible(UseTemplateCtorNoMove, UseTemplateCtorNoMove &&), ""); + +struct TemplateCtorNoMoveSFINAE { + TemplateCtorNoMoveSFINAE(const TemplateCtorNoMoveSFINAE &) = default; + template<typename T, typename U = typename T::error> TemplateCtorNoMoveSFINAE(T &&); +}; +static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, const TemplateCtorNoMoveSFINAE &), ""); +static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, TemplateCtorNoMoveSFINAE &&), ""); + +struct UseTemplateCtorNoMoveSFINAE { + TemplateCtorNoMoveSFINAE tcnm; +}; +static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, const UseTemplateCtorNoMoveSFINAE &), ""); +static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, UseTemplateCtorNoMoveSFINAE &&), ""); + +namespace TrivialityDependsOnImplicitDeletion { + struct PrivateMove { + PrivateMove(const PrivateMove &) = default; + private: + PrivateMove(PrivateMove &&); + friend class Access; + }; + static_assert(__is_trivially_constructible(PrivateMove, const PrivateMove &), ""); + static_assert(!__is_trivially_constructible(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_constructible(NoAccess, const NoAccess &), ""); + static_assert(__is_trivially_constructible(NoAccess, NoAccess &&), ""); + struct TopNoAccess : NoAccess {}; + static_assert(__is_trivially_constructible(TopNoAccess, const TopNoAccess &), ""); + static_assert(__is_trivially_constructible(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_constructible(Access, const Access &), ""); + static_assert(!__is_trivially_constructible(Access, Access &&), ""); + struct TopAccess : Access {}; + static_assert(__is_trivially_constructible(TopAccess, const TopAccess &), ""); + static_assert(!__is_trivially_constructible(TopAccess, TopAccess &&), ""); +} + +namespace TrivialityDependsOnDestructor { + class HasInaccessibleDestructor { ~HasInaccessibleDestructor() = default; }; + struct HasImplicitlyDeletedDestructor : HasInaccessibleDestructor {}; + struct HasImplicitlyDeletedCopyCtor : HasImplicitlyDeletedDestructor { + HasImplicitlyDeletedCopyCtor() = default; + template<typename T> HasImplicitlyDeletedCopyCtor(T &&); + // Copy ctor is deleted but trivial. + // Move ctor is suppressed. + HasImplicitlyDeletedCopyCtor(const HasImplicitlyDeletedCopyCtor&) = default; + HasImplicitlyDeletedCopyCtor(HasImplicitlyDeletedCopyCtor&&) = default; + }; + struct Test : HasImplicitlyDeletedCopyCtor { + Test(const Test&) = default; + Test(Test&&) = default; + }; + // Implicit copy ctor calls deleted trivial copy ctor. + static_assert(__has_trivial_copy(Test), ""); + // This is false because the destructor is deleted. + static_assert(!__is_trivially_constructible(Test, const Test &), ""); + // Implicit move ctor calls template ctor. + static_assert(!__is_trivially_constructible(Test, Test &&), ""); + + struct HasAccessibleDestructor { ~HasAccessibleDestructor() = default; }; + struct HasImplicitlyDefaultedDestructor : HasAccessibleDestructor {}; + struct HasImplicitlyDefaultedCopyCtor : HasImplicitlyDefaultedDestructor { + template<typename T> HasImplicitlyDefaultedCopyCtor(T &&); + // Copy ctor is trivial. + // Move ctor is trivial. + }; + struct Test2 : HasImplicitlyDefaultedCopyCtor {}; + // Implicit copy ctor calls trivial copy ctor. + static_assert(__has_trivial_copy(Test2), ""); + static_assert(__is_trivially_constructible(Test2, const Test2 &), ""); + // Implicit move ctor calls trivial move ctor. + static_assert(__is_trivially_constructible(Test2, Test2 &&), ""); +} diff --git a/test/CXX/special/class.copy/p18-cxx11.cpp b/test/CXX/special/class.copy/p18-cxx11.cpp new file mode 100644 index 0000000..7b09dd6 --- /dev/null +++ b/test/CXX/special/class.copy/p18-cxx11.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify +// expected-no-diagnostics + +// C++98 [class.copy]p10 / C++11 [class.copy]p18. + +// The implicitly-declared copy assignment operator for a class X will have the form +// X& X::operator=(const X&) +// if [every direct subobject] has a copy assignment operator whose first parameter is +// of type 'const volatile[opt] T &' or 'T'. Otherwise, it will have the form +// X &X::operator=(X&) + +struct ConstCopy { + ConstCopy &operator=(const ConstCopy &); +}; + +struct NonConstCopy { + NonConstCopy &operator=(NonConstCopy &); +}; + +struct DeletedConstCopy { + DeletedConstCopy &operator=(const DeletedConstCopy &) = delete; +}; + +struct DeletedNonConstCopy { + DeletedNonConstCopy &operator=(DeletedNonConstCopy &) = delete; +}; + +struct ImplicitlyDeletedConstCopy { + ImplicitlyDeletedConstCopy &operator=(ImplicitlyDeletedConstCopy &&); +}; + +struct ByValueCopy { + ByValueCopy &operator=(ByValueCopy); +}; + +struct AmbiguousConstCopy { + AmbiguousConstCopy &operator=(const AmbiguousConstCopy&); + AmbiguousConstCopy &operator=(AmbiguousConstCopy); +}; + + +struct A : ConstCopy {}; +struct B : NonConstCopy { ConstCopy a; }; +struct C : ConstCopy { NonConstCopy a; }; +struct D : DeletedConstCopy {}; +struct E : DeletedNonConstCopy {}; +struct F { ImplicitlyDeletedConstCopy a; }; +struct G : virtual B {}; +struct H : ByValueCopy {}; +struct I : AmbiguousConstCopy {}; + +struct Test { + friend A &A::operator=(const A &); + friend B &B::operator=(B &); + friend C &C::operator=(C &); + friend D &D::operator=(const D &); + friend E &E::operator=(E &); + friend F &F::operator=(const F &); + friend G &G::operator=(G &); + friend H &H::operator=(const H &); + friend I &I::operator=(const I &); +}; diff --git a/test/CXX/special/class.copy/p23-cxx11.cpp b/test/CXX/special/class.copy/p23-cxx11.cpp index 7c04a82..90945c5 100644 --- a/test/CXX/special/class.copy/p23-cxx11.cpp +++ b/test/CXX/special/class.copy/p23-cxx11.cpp @@ -143,6 +143,6 @@ namespace PR13381 { }; void g() { T t; - t = T(); // expected-error{{implicitly-deleted copy assignment}} + t = T(); // expected-error{{object of type 'PR13381::T' cannot be assigned because its copy assignment operator is implicitly deleted}} } } diff --git a/test/CXX/special/class.copy/p25-0x.cpp b/test/CXX/special/class.copy/p25-0x.cpp new file mode 100644 index 0000000..c7224ae --- /dev/null +++ b/test/CXX/special/class.copy/p25-0x.cpp @@ -0,0 +1,202 @@ +// 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 &&), ""); +} diff --git a/test/CXX/special/class.copy/p28-cxx11.cpp b/test/CXX/special/class.copy/p28-cxx11.cpp new file mode 100644 index 0000000..dc501d9 --- /dev/null +++ b/test/CXX/special/class.copy/p28-cxx11.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++98 %s -fsyntax-only +// RUN: %clang_cc1 -std=c++11 %s -verify + +// In C++11, we must perform overload resolution to determine which function is +// called by a defaulted assignment operator, and the selected operator might +// not be a copy or move assignment (it might be a specialization of a templated +// 'operator=', for instance). +struct A { + A &operator=(const A &); + + template<typename T> + A &operator=(T &&) { return T::error; } // expected-error {{no member named 'error' in 'A'}} +}; + +struct B : A { + B &operator=(B &&); +}; + +B &B::operator=(B &&) = default; // expected-note {{here}} |