// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // Tests for implicit (non-)declaration of move constructor and // assignment: p9, p11, p20, p23. // This class, used as a member, allows to distinguish move from copy because // move operations are no-throw, copy operations aren't. struct ThrowingCopy { ThrowingCopy() noexcept; ThrowingCopy(ThrowingCopy &&) noexcept; ThrowingCopy(const ThrowingCopy &) noexcept(false); ThrowingCopy & operator =(ThrowingCopy &&) noexcept; ThrowingCopy & operator =(const ThrowingCopy &) noexcept(false); }; struct HasCopyConstructor { ThrowingCopy tc; HasCopyConstructor() noexcept; HasCopyConstructor(const HasCopyConstructor &) noexcept(false); }; struct HasCopyAssignment { ThrowingCopy tc; HasCopyAssignment() noexcept; HasCopyAssignment & operator =(const HasCopyAssignment &) noexcept(false); }; struct HasMoveConstructor { ThrowingCopy tc; HasMoveConstructor() noexcept; HasMoveConstructor(HasMoveConstructor &&) noexcept; // expected-note {{copy assignment operator is implicitly deleted because 'HasMoveConstructor' has a user-declared move constructor}} }; struct HasMoveAssignment { // expected-note {{implicit copy constructor}} ThrowingCopy tc; HasMoveAssignment() noexcept; HasMoveAssignment & operator =(HasMoveAssignment &&) noexcept; }; struct HasDestructor { ThrowingCopy tc; HasDestructor() noexcept; ~HasDestructor() noexcept; }; void test_basic_exclusion() { static_assert(!noexcept(HasCopyConstructor((HasCopyConstructor()))), ""); HasCopyConstructor hcc; static_assert(!noexcept(hcc = HasCopyConstructor()), ""); static_assert(!noexcept(HasCopyAssignment((HasCopyAssignment()))), ""); HasCopyAssignment hca; static_assert(!noexcept(hca = HasCopyAssignment()), ""); static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), ""); HasMoveConstructor hmc; 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; static_assert(noexcept(hma = HasMoveAssignment()), ""); static_assert(!noexcept(HasDestructor((HasDestructor()))), ""); HasDestructor hd; static_assert(!noexcept(hd = HasDestructor()), ""); } struct PrivateMove { PrivateMove() noexcept; PrivateMove(const PrivateMove &) noexcept(false); PrivateMove & operator =(const PrivateMove &) noexcept(false); private: PrivateMove(PrivateMove &&) noexcept; PrivateMove & operator =(PrivateMove &&) noexcept; }; struct InheritsPrivateMove : PrivateMove {}; struct ContainsPrivateMove { PrivateMove pm; }; struct PrivateDestructor { PrivateDestructor() noexcept; PrivateDestructor(const PrivateDestructor &) noexcept(false); PrivateDestructor(PrivateDestructor &&) noexcept; private: ~PrivateDestructor() noexcept; }; struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note{{base class 'PrivateDestructor' has an inaccessible destructor}} struct ContainsPrivateDestructor { PrivateDestructor pd; // expected-note{{field 'pd' has an inaccessible destructor}} }; struct NonTrivialCopyOnly { NonTrivialCopyOnly() noexcept; NonTrivialCopyOnly(const NonTrivialCopyOnly &) noexcept(false); NonTrivialCopyOnly & operator =(const NonTrivialCopyOnly &) noexcept(false); }; struct InheritsNonTrivialCopyOnly : NonTrivialCopyOnly {}; struct ContainsNonTrivialCopyOnly { NonTrivialCopyOnly ntco; }; struct ContainsConst { const int i; ContainsConst() noexcept; ContainsConst & operator =(ContainsConst &); // expected-note {{not viable}} }; struct ContainsRef { int &i; ContainsRef() noexcept; ContainsRef & operator =(ContainsRef &); // expected-note {{not viable}} }; struct Base { Base & operator =(Base &); }; struct DirectVirtualBase : virtual Base {}; // expected-note {{copy assignment operator) not viable}} struct IndirectVirtualBase : DirectVirtualBase {}; // expected-note {{copy assignment operator) not viable}} void test_deletion_exclusion() { // FIXME: How to test the union thing? static_assert(!noexcept(InheritsPrivateMove(InheritsPrivateMove())), ""); static_assert(!noexcept(ContainsPrivateMove(ContainsPrivateMove())), ""); InheritsPrivateMove ipm; static_assert(!noexcept(ipm = InheritsPrivateMove()), ""); ContainsPrivateMove cpm; static_assert(!noexcept(cpm = ContainsPrivateMove()), ""); (InheritsPrivateDestructor(InheritsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}} (ContainsPrivateDestructor(ContainsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}} static_assert(!noexcept(InheritsNonTrivialCopyOnly(InheritsNonTrivialCopyOnly())), ""); static_assert(!noexcept(ContainsNonTrivialCopyOnly(ContainsNonTrivialCopyOnly())), ""); InheritsNonTrivialCopyOnly intco; static_assert(!noexcept(intco = InheritsNonTrivialCopyOnly()), ""); ContainsNonTrivialCopyOnly cntco; static_assert(!noexcept(cntco = ContainsNonTrivialCopyOnly()), ""); ContainsConst cc; cc = ContainsConst(); // expected-error {{no viable}} ContainsRef cr; cr = ContainsRef(); // expected-error {{no viable}} DirectVirtualBase dvb; dvb = DirectVirtualBase(); // expected-error {{no viable}} IndirectVirtualBase ivb; ivb = IndirectVirtualBase(); // expected-error {{no viable}} } struct ContainsRValueRef { int&& ri; ContainsRValueRef() noexcept; }; void test_contains_rref() { (ContainsRValueRef(ContainsRValueRef())); } namespace DR1402 { struct NonTrivialCopyCtor { NonTrivialCopyCtor(const NonTrivialCopyCtor &); }; struct NonTrivialCopyAssign { NonTrivialCopyAssign &operator=(const NonTrivialCopyAssign &); }; struct NonTrivialCopyCtorVBase : virtual NonTrivialCopyCtor { NonTrivialCopyCtorVBase(NonTrivialCopyCtorVBase &&); NonTrivialCopyCtorVBase &operator=(NonTrivialCopyCtorVBase &&) = default; }; struct NonTrivialCopyAssignVBase : virtual NonTrivialCopyAssign { NonTrivialCopyAssignVBase(NonTrivialCopyAssignVBase &&); NonTrivialCopyAssignVBase &operator=(NonTrivialCopyAssignVBase &&) = default; }; struct NonTrivialMoveAssign { NonTrivialMoveAssign(NonTrivialMoveAssign&&); NonTrivialMoveAssign &operator=(NonTrivialMoveAssign &&); }; struct NonTrivialMoveAssignVBase : virtual NonTrivialMoveAssign { NonTrivialMoveAssignVBase(NonTrivialMoveAssignVBase &&); NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&) = default; }; // DR1402: A non-movable, non-trivially-copyable class type as a subobject no // longer inhibits the declaration of a move operation. struct NoMove1 { NonTrivialCopyCtor ntcc; }; struct NoMove2 { NonTrivialCopyAssign ntcc; }; struct NoMove3 : NonTrivialCopyCtor {}; struct NoMove4 : NonTrivialCopyAssign {}; struct NoMove5 : virtual NonTrivialCopyCtor {}; struct NoMove6 : virtual NonTrivialCopyAssign {}; struct NoMove7 : NonTrivialCopyCtorVBase {}; struct NoMove8 : NonTrivialCopyAssignVBase {}; // DR1402: A non-trivially-move-assignable virtual base class no longer // inhibits the declaration of a move assignment (even though it might // move-assign the base class multiple times). struct NoMove9 : NonTrivialMoveAssign {}; struct NoMove10 : virtual NonTrivialMoveAssign {}; struct NoMove11 : NonTrivialMoveAssignVBase {}; template<typename T> void test(T t) { (void)T(static_cast<T&&>(t)); // ok t = static_cast<T&&>(t); // ok } template void test(NoMove1); template void test(NoMove2); template void test(NoMove3); template void test(NoMove4); template void test(NoMove5); template void test(NoMove6); template void test(NoMove7); template void test(NoMove8); template void test(NoMove9); template void test(NoMove10); template void test(NoMove11); struct CopyOnly { CopyOnly(const CopyOnly&); CopyOnly &operator=(const CopyOnly&); }; struct MoveOnly { MoveOnly(MoveOnly&&); // expected-note {{user-declared move}} MoveOnly &operator=(MoveOnly&&); }; template void test(CopyOnly); // ok, copies template void test(MoveOnly); // ok, moves struct CopyAndMove { // expected-note {{implicitly deleted}} CopyOnly co; MoveOnly mo; // expected-note {{deleted copy}} }; template void test(CopyAndMove); // ok, copies co, moves mo void test2(CopyAndMove cm) { (void)CopyAndMove(cm); // expected-error {{deleted}} cm = cm; // expected-error {{deleted}} } namespace VbaseMove { struct A {}; struct B { B &operator=(B&&); }; struct C { C &operator=(const C&); }; struct D { B b; }; template<typename T, unsigned I, bool NonTrivialMove = false> struct E : virtual T {}; template<typename T, unsigned I> struct E<T, I, true> : virtual T { E &operator=(E&&); }; template<typename T> struct F : E<T, 0>, // expected-note-re 2{{'{{[BD]}}' is a virtual base class of base class 'E<}} E<T, 1> {}; // expected-note-re 2{{'{{[BD]}}' is a virtual base class of base class 'E<}} template<typename T> struct G : E<T, 0, true>, E<T, 0> {}; template<typename T> struct H : E<T, 0, true>, E<T, 1, true> {}; template<typename T> struct I : E<T, 0>, T {}; template<typename T> struct J : E<T, 0>, // expected-note-re 2{{'{{[BD]}}' is a virtual base class of base class 'E<}} virtual T {}; // expected-note-re 2{{virtual base class '{{[BD]}}' declared here}} template<typename T> void move(T t) { t = static_cast<T&&>(t); } // expected-warning-re@-1 4{{defaulted move assignment operator of {{.*}} will move assign virtual base class '{{[BD]}}' multiple times}} template void move(F<A>); template void move(F<B>); // expected-note {{in instantiation of}} template void move(F<C>); template void move(F<D>); // expected-note {{in instantiation of}} template void move(G<A>); template void move(G<B>); template void move(G<C>); template void move(G<D>); template void move(H<A>); template void move(H<B>); template void move(H<C>); template void move(H<D>); template void move(I<A>); template void move(I<B>); template void move(I<C>); template void move(I<D>); template void move(J<A>); template void move(J<B>); // expected-note {{in instantiation of}} template void move(J<C>); template void move(J<D>); // expected-note {{in instantiation of}} } } namespace PR12625 { struct X; // expected-note {{forward decl}} struct Y { X x; // expected-error {{incomplete}} } y = Y(); }