| // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base %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(); |
| } |