implicit-move.cpp revision 33b1f634e074835a1b49c23d2b7674161fef1762
1// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
2
3// Tests for implicit (non-)declaration of move constructor and
4// assignment: p9, p11, p20, p23.
5
6// This class, used as a member, allows to distinguish move from copy because
7// move operations are no-throw, copy operations aren't.
8struct ThrowingCopy {
9  ThrowingCopy() noexcept;
10  ThrowingCopy(ThrowingCopy &&) noexcept;
11  ThrowingCopy(const ThrowingCopy &) noexcept(false);
12  ThrowingCopy & operator =(ThrowingCopy &&) noexcept;
13  ThrowingCopy & operator =(const ThrowingCopy &) noexcept(false);
14};
15
16struct HasCopyConstructor {
17  ThrowingCopy tc;
18  HasCopyConstructor() noexcept;
19  HasCopyConstructor(const HasCopyConstructor &) noexcept(false);
20};
21
22struct HasCopyAssignment {
23  ThrowingCopy tc;
24  HasCopyAssignment() noexcept;
25  HasCopyAssignment & operator =(const HasCopyAssignment &) noexcept(false);
26};
27
28struct HasMoveConstructor {
29  ThrowingCopy tc;
30  HasMoveConstructor() noexcept;
31  HasMoveConstructor(HasMoveConstructor &&) noexcept; // expected-note {{copy assignment operator is implicitly deleted because 'HasMoveConstructor' has a user-declared move constructor}}
32};
33
34struct HasMoveAssignment { // expected-note {{implicit copy constructor}}
35  ThrowingCopy tc;
36  HasMoveAssignment() noexcept;
37  HasMoveAssignment & operator =(HasMoveAssignment &&) noexcept;
38};
39
40struct HasDestructor {
41  ThrowingCopy tc;
42  HasDestructor() noexcept;
43  ~HasDestructor() noexcept;
44};
45
46void test_basic_exclusion() {
47  static_assert(!noexcept(HasCopyConstructor((HasCopyConstructor()))), "");
48  HasCopyConstructor hcc;
49  static_assert(!noexcept(hcc = HasCopyConstructor()), "");
50
51  static_assert(!noexcept(HasCopyAssignment((HasCopyAssignment()))), "");
52  HasCopyAssignment hca;
53  static_assert(!noexcept(hca = HasCopyAssignment()), "");
54
55  static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), "");
56  HasMoveConstructor hmc;
57  hmc = HasMoveConstructor(); // expected-error {{object of type 'HasMoveConstructor' cannot be assigned because its copy assignment operator is implicitly deleted}}
58
59  (HasMoveAssignment(HasMoveAssignment())); // expected-error {{uses deleted function}}
60  HasMoveAssignment hma;
61  static_assert(noexcept(hma = HasMoveAssignment()), "");
62
63  static_assert(!noexcept(HasDestructor((HasDestructor()))), "");
64  HasDestructor hd;
65  static_assert(!noexcept(hd = HasDestructor()), "");
66}
67
68struct PrivateMove {
69  PrivateMove() noexcept;
70  PrivateMove(const PrivateMove &) noexcept(false);
71  PrivateMove & operator =(const PrivateMove &) noexcept(false);
72private:
73  PrivateMove(PrivateMove &&) noexcept;
74  PrivateMove & operator =(PrivateMove &&) noexcept;
75};
76
77struct InheritsPrivateMove : PrivateMove {};
78struct ContainsPrivateMove {
79  PrivateMove pm;
80};
81
82struct PrivateDestructor {
83  PrivateDestructor() noexcept;
84  PrivateDestructor(const PrivateDestructor &) noexcept(false);
85  PrivateDestructor(PrivateDestructor &&) noexcept;
86private:
87  ~PrivateDestructor() noexcept;
88};
89
90struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note{{base class 'PrivateDestructor' has an inaccessible destructor}}
91struct ContainsPrivateDestructor {
92  PrivateDestructor pd; // expected-note{{field 'pd' has an inaccessible destructor}}
93};
94
95struct NonTrivialCopyOnly {
96  NonTrivialCopyOnly() noexcept;
97  NonTrivialCopyOnly(const NonTrivialCopyOnly &) noexcept(false);
98  NonTrivialCopyOnly & operator =(const NonTrivialCopyOnly &) noexcept(false);
99};
100
101struct InheritsNonTrivialCopyOnly : NonTrivialCopyOnly {};
102struct ContainsNonTrivialCopyOnly {
103  NonTrivialCopyOnly ntco;
104};
105
106struct ContainsConst {
107  const int i;
108  ContainsConst() noexcept;
109  ContainsConst & operator =(ContainsConst &); // expected-note {{not viable}}
110};
111
112struct ContainsRef {
113  int &i;
114  ContainsRef() noexcept;
115  ContainsRef & operator =(ContainsRef &); // expected-note {{not viable}}
116};
117
118struct Base {
119  Base & operator =(Base &);
120};
121struct DirectVirtualBase : virtual Base {}; // expected-note {{copy assignment operator) not viable}}
122struct IndirectVirtualBase : DirectVirtualBase {}; // expected-note {{copy assignment operator) not viable}}
123
124void test_deletion_exclusion() {
125  // FIXME: How to test the union thing?
126
127  static_assert(!noexcept(InheritsPrivateMove(InheritsPrivateMove())), "");
128  static_assert(!noexcept(ContainsPrivateMove(ContainsPrivateMove())), "");
129  InheritsPrivateMove ipm;
130  static_assert(!noexcept(ipm = InheritsPrivateMove()), "");
131  ContainsPrivateMove cpm;
132  static_assert(!noexcept(cpm = ContainsPrivateMove()), "");
133
134  (InheritsPrivateDestructor(InheritsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}}
135  (ContainsPrivateDestructor(ContainsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}}
136
137  static_assert(!noexcept(InheritsNonTrivialCopyOnly(InheritsNonTrivialCopyOnly())), "");
138  static_assert(!noexcept(ContainsNonTrivialCopyOnly(ContainsNonTrivialCopyOnly())), "");
139  InheritsNonTrivialCopyOnly intco;
140  static_assert(!noexcept(intco = InheritsNonTrivialCopyOnly()), "");
141  ContainsNonTrivialCopyOnly cntco;
142  static_assert(!noexcept(cntco = ContainsNonTrivialCopyOnly()), "");
143
144  ContainsConst cc;
145  cc = ContainsConst(); // expected-error {{no viable}}
146
147  ContainsRef cr;
148  cr = ContainsRef(); // expected-error {{no viable}}
149
150  DirectVirtualBase dvb;
151  dvb = DirectVirtualBase(); // expected-error {{no viable}}
152
153  IndirectVirtualBase ivb;
154  ivb = IndirectVirtualBase(); // expected-error {{no viable}}
155}
156
157struct ContainsRValueRef {
158  int&& ri;
159  ContainsRValueRef() noexcept;
160};
161
162void test_contains_rref() {
163  (ContainsRValueRef(ContainsRValueRef()));
164}
165
166
167namespace DR1402 {
168  struct NonTrivialCopyCtor {
169    NonTrivialCopyCtor(const NonTrivialCopyCtor &);
170  };
171  struct NonTrivialCopyAssign {
172    NonTrivialCopyAssign &operator=(const NonTrivialCopyAssign &);
173  };
174
175  struct NonTrivialCopyCtorVBase : virtual NonTrivialCopyCtor {
176    NonTrivialCopyCtorVBase(NonTrivialCopyCtorVBase &&);
177    NonTrivialCopyCtorVBase &operator=(NonTrivialCopyCtorVBase &&) = default;
178  };
179  struct NonTrivialCopyAssignVBase : virtual NonTrivialCopyAssign {
180    NonTrivialCopyAssignVBase(NonTrivialCopyAssignVBase &&);
181    NonTrivialCopyAssignVBase &operator=(NonTrivialCopyAssignVBase &&) = default;
182  };
183
184  struct NonTrivialMoveAssign {
185    NonTrivialMoveAssign(NonTrivialMoveAssign&&);
186    NonTrivialMoveAssign &operator=(NonTrivialMoveAssign &&);
187  };
188  struct NonTrivialMoveAssignVBase : virtual NonTrivialMoveAssign {
189    NonTrivialMoveAssignVBase(NonTrivialMoveAssignVBase &&);
190    NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&) = default;
191  };
192
193  // DR1402: A non-movable, non-trivially-copyable class type as a subobject no
194  // longer inhibits the declaration of a move operation.
195  struct NoMove1 { NonTrivialCopyCtor ntcc; };
196  struct NoMove2 { NonTrivialCopyAssign ntcc; };
197  struct NoMove3 : NonTrivialCopyCtor {};
198  struct NoMove4 : NonTrivialCopyAssign {};
199  struct NoMove5 : virtual NonTrivialCopyCtor {};
200  struct NoMove6 : virtual NonTrivialCopyAssign {};
201  struct NoMove7 : NonTrivialCopyCtorVBase {};
202  struct NoMove8 : NonTrivialCopyAssignVBase {};
203
204  // DR1402: A non-trivially-move-assignable virtual base class no longer
205  // inhibits the declaration of a move assignment (even though it might
206  // move-assign the base class multiple times).
207  struct NoMove9 : NonTrivialMoveAssign {};
208  struct NoMove10 : virtual NonTrivialMoveAssign {};
209  struct NoMove11 : NonTrivialMoveAssignVBase {};
210
211  template<typename T> void test(T t) {
212    (void)T(static_cast<T&&>(t)); // ok
213    t = static_cast<T&&>(t); // ok
214  }
215  template void test(NoMove1);
216  template void test(NoMove2);
217  template void test(NoMove3);
218  template void test(NoMove4);
219  template void test(NoMove5);
220  template void test(NoMove6);
221  template void test(NoMove7);
222  template void test(NoMove8);
223  template void test(NoMove9);
224  template void test(NoMove10);
225  template void test(NoMove11);
226
227  struct CopyOnly {
228    CopyOnly(const CopyOnly&);
229    CopyOnly &operator=(const CopyOnly&);
230  };
231  struct MoveOnly {
232    MoveOnly(MoveOnly&&); // expected-note {{user-declared move}}
233    MoveOnly &operator=(MoveOnly&&);
234  };
235  template void test(CopyOnly); // ok, copies
236  template void test(MoveOnly); // ok, moves
237  struct CopyAndMove { // expected-note {{implicitly deleted}}
238    CopyOnly co;
239    MoveOnly mo; // expected-note {{deleted copy}}
240  };
241  template void test(CopyAndMove); // ok, copies co, moves mo
242  void test2(CopyAndMove cm) {
243    (void)CopyAndMove(cm); // expected-error {{deleted}}
244    cm = cm; // expected-error {{deleted}}
245  }
246
247  namespace VbaseMove {
248    struct A {};
249    struct B { B &operator=(B&&); };
250    struct C { C &operator=(const C&); };
251    struct D { B b; };
252
253    template<typename T, unsigned I, bool NonTrivialMove = false>
254    struct E : virtual T {};
255
256    template<typename T, unsigned I>
257    struct E<T, I, true> : virtual T { E &operator=(E&&); };
258
259    template<typename T>
260    struct F :
261      E<T, 0>, // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
262      E<T, 1> {}; // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
263
264    template<typename T>
265    struct G : E<T, 0, true>, E<T, 0> {};
266
267    template<typename T>
268    struct H : E<T, 0, true>, E<T, 1, true> {};
269
270    template<typename T>
271    struct I : E<T, 0>, T {};
272
273    template<typename T>
274    struct J :
275      E<T, 0>, // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
276      virtual T {}; // expected-note-re 2{{virtual base class '[BD]' declared here}}
277
278    template<typename T> void move(T t) { t = static_cast<T&&>(t); }
279    // expected-warning-re@-1 4{{defaulted move assignment operator of .* will move assign virtual base class '[BD]' multiple times}}
280    template void move(F<A>);
281    template void move(F<B>); // expected-note {{in instantiation of}}
282    template void move(F<C>);
283    template void move(F<D>); // expected-note {{in instantiation of}}
284    template void move(G<A>);
285    template void move(G<B>);
286    template void move(G<C>);
287    template void move(G<D>);
288    template void move(H<A>);
289    template void move(H<B>);
290    template void move(H<C>);
291    template void move(H<D>);
292    template void move(I<A>);
293    template void move(I<B>);
294    template void move(I<C>);
295    template void move(I<D>);
296    template void move(J<A>);
297    template void move(J<B>); // expected-note {{in instantiation of}}
298    template void move(J<C>);
299    template void move(J<D>); // expected-note {{in instantiation of}}
300  }
301}
302
303namespace PR12625 {
304  struct X; // expected-note {{forward decl}}
305  struct Y {
306    X x; // expected-error {{incomplete}}
307  } y = Y();
308}
309