309 lines
10 KiB
C++
309 lines
10 KiB
C++
|
// 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();
|
||
|
}
|