1 // This test enumerates various cases of interest for partial
2 // [re]initialization of ADTs and tuples.
3 //
4 // See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987.
5 //
6 // All of tests in this file are expected to change from being
7 // rejected, at least under NLL (by rust-lang/rust#54986) to being
8 // **accepted** when rust-lang/rust#54987 is implemented.
9 // (That's why there are assertions in the code.)
10 //
11 // See issue-21232-partial-init-and-erroneous-use.rs for cases of
12 // tests that are meant to continue failing to compile once
13 // rust-lang/rust#54987 is implemented.
14 
15 struct S<Y> {
16     x: u32,
17 
18     // Note that even though `y` may implement `Drop`, under #54987 we
19     // will still allow partial initialization of `S` itself.
20     y: Y,
21 }
22 
23 enum Void { }
24 
25 type B = Box<u32>;
26 
new() -> Self27 impl S<B> { fn new() -> Self { S { x: 0, y: Box::new(0) } } }
28 
borrow_s(s: &S<B>)29 fn borrow_s(s: &S<B>) { assert_eq!(s.x, 10); assert_eq!(*s.y, 20); }
move_s(s: S<B>)30 fn move_s(s: S<B>) {  assert_eq!(s.x, 10); assert_eq!(*s.y, 20); }
borrow_field(x: &u32)31 fn borrow_field(x: &u32) { assert_eq!(*x, 10); }
32 
33 type T = (u32, B);
34 type Tvoid = (u32, Void);
35 
borrow_t(t: &T)36 fn borrow_t(t: &T) { assert_eq!(t.0, 10); assert_eq!(*t.1, 20); }
move_t(t: T)37 fn move_t(t: T) {  assert_eq!(t.0, 10); assert_eq!(*t.1, 20); }
38 
39 struct Q<F> {
40     v: u32,
41     r: R<F>,
42 }
43 
44 struct R<F> {
45     w: u32,
46     f: F,
47 }
48 
new(f: F) -> Self49 impl<F> Q<F> { fn new(f: F) -> Self { Q { v: 0, r: R::new(f) } } }
new(f: F) -> Self50 impl<F> R<F> { fn new(f: F) -> Self { R { w: 0, f } } }
51 
52 // Axes to cover:
53 // * local/field: Is the structure in a local or a field
54 // * fully/partial/void: Are we fully initializing it before using any part?
55 //                       Is whole type empty due to a void component?
56 // * init/reinit: First initialization, or did we previously inititalize and then move out?
57 // * struct/tuple: Is this a struct or a (X, Y).
58 //
59 // As a shorthand for the cases above, adding a numeric summary to
60 // each test's fn name to denote each point on each axis.
61 //
62 // e.g., 1000 = field fully init struct; 0211 = local void reinit tuple
63 
64 // It got pretty monotonous writing the same code over and over, and I
65 // feared I would forget details. So I abstracted some desiderata into
66 // macros. But I left the initialization code inline, because that's
67 // where the errors for #54986 will be emitted.
68 
69 macro_rules! use_fully {
70     (struct $s:expr) => { {
71         borrow_field(& $s.x );
72         borrow_s(& $s );
73         move_s( $s );
74     } };
75 
76     (tuple $t:expr) => { {
77         borrow_field(& $t.0 );
78         borrow_t(& $t );
79         move_t( $t );
80     } }
81 }
82 
83 macro_rules! use_part {
84     (struct $s:expr) => { {
85         borrow_field(& $s.x );
86         match $s { S { ref x, y: _ } => { borrow_field(x); } }
87     } };
88 
89     (tuple $t:expr) => { {
90         borrow_field(& $t.0 );
91         match $t { (ref x, _) => { borrow_field(x); } }
92     } }
93 }
94 
test_0000_local_fully_init_and_use_struct()95 fn test_0000_local_fully_init_and_use_struct() {
96     let s: S<B>;
97     s.x = 10; s.y = Box::new(20);
98     //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381]
99     use_fully!(struct s);
100 }
101 
test_0001_local_fully_init_and_use_tuple()102 fn test_0001_local_fully_init_and_use_tuple() {
103     let t: T;
104     t.0 = 10; t.1 = Box::new(20);
105     //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
106     use_fully!(tuple t);
107 }
108 
test_0010_local_fully_reinit_and_use_struct()109 fn test_0010_local_fully_reinit_and_use_struct() {
110     let mut s: S<B> = S::new(); drop(s);
111     s.x = 10; s.y = Box::new(20);
112     //~^ ERROR assign to part of moved value: `s` [E0382]
113     use_fully!(struct s);
114 }
115 
test_0011_local_fully_reinit_and_use_tuple()116 fn test_0011_local_fully_reinit_and_use_tuple() {
117     let mut t: T = (0, Box::new(0)); drop(t);
118     t.0 = 10; t.1 = Box::new(20);
119     //~^ ERROR assign to part of moved value: `t` [E0382]
120     use_fully!(tuple t);
121 }
122 
test_0100_local_partial_init_and_use_struct()123 fn test_0100_local_partial_init_and_use_struct() {
124     let s: S<B>;
125     s.x = 10;
126     //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381]
127     use_part!(struct s);
128 }
129 
test_0101_local_partial_init_and_use_tuple()130 fn test_0101_local_partial_init_and_use_tuple() {
131     let t: T;
132     t.0 = 10;
133     //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
134     use_part!(tuple t);
135 }
136 
test_0110_local_partial_reinit_and_use_struct()137 fn test_0110_local_partial_reinit_and_use_struct() {
138     let mut s: S<B> = S::new(); drop(s);
139     s.x = 10;
140     //~^ ERROR assign to part of moved value: `s` [E0382]
141     use_part!(struct s);
142 }
143 
test_0111_local_partial_reinit_and_use_tuple()144 fn test_0111_local_partial_reinit_and_use_tuple() {
145     let mut t: T = (0, Box::new(0)); drop(t);
146     t.0 = 10;
147     //~^ ERROR assign to part of moved value: `t` [E0382]
148     use_part!(tuple t);
149 }
150 
test_0200_local_void_init_and_use_struct()151 fn test_0200_local_void_init_and_use_struct() {
152     let s: S<Void>;
153     s.x = 10;
154     //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381]
155     use_part!(struct s);
156 }
157 
test_0201_local_void_init_and_use_tuple()158 fn test_0201_local_void_init_and_use_tuple() {
159     let t: Tvoid;
160     t.0 = 10;
161     //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
162     use_part!(tuple t);
163 }
164 
165 // NOTE: uniform structure of tests here makes n21n (aka combining
166 // Void with Reinit) an (even more) senseless case, as we cannot
167 // safely create initial instance containing Void to move out of and
168 // then reinitialize. While I was tempted to sidestep this via some
169 // unsafe code (eek), lets just instead not encode such tests.
170 
171 // fn test_0210_local_void_reinit_and_use_struct() { unimplemented!() }
172 // fn test_0211_local_void_reinit_and_use_tuple() { unimplemented!() }
173 
test_1000_field_fully_init_and_use_struct()174 fn test_1000_field_fully_init_and_use_struct() {
175     let q: Q<S<B>>;
176     q.r.f.x = 10; q.r.f.y = Box::new(20);
177     //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
178     use_fully!(struct q.r.f);
179 }
180 
test_1001_field_fully_init_and_use_tuple()181 fn test_1001_field_fully_init_and_use_tuple() {
182     let q: Q<T>;
183     q.r.f.0 = 10; q.r.f.1 = Box::new(20);
184     //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
185     use_fully!(tuple q.r.f);
186 }
187 
test_1010_field_fully_reinit_and_use_struct()188 fn test_1010_field_fully_reinit_and_use_struct() {
189     let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
190     q.r.f.x = 10; q.r.f.y = Box::new(20);
191     //~^ ERROR assign to part of moved value: `q.r` [E0382]
192     use_fully!(struct q.r.f);
193 }
194 
test_1011_field_fully_reinit_and_use_tuple()195 fn test_1011_field_fully_reinit_and_use_tuple() {
196     let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
197     q.r.f.0 = 10; q.r.f.1 = Box::new(20);
198     //~^ ERROR assign to part of moved value: `q.r` [E0382]
199     use_fully!(tuple q.r.f);
200 }
201 
test_1100_field_partial_init_and_use_struct()202 fn test_1100_field_partial_init_and_use_struct() {
203     let q: Q<S<B>>;
204     q.r.f.x = 10;
205     //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
206     use_part!(struct q.r.f);
207 }
208 
test_1101_field_partial_init_and_use_tuple()209 fn test_1101_field_partial_init_and_use_tuple() {
210     let q: Q<T>;
211     q.r.f.0 = 10;
212     //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
213     use_part!(tuple q.r.f);
214 }
215 
test_1110_field_partial_reinit_and_use_struct()216 fn test_1110_field_partial_reinit_and_use_struct() {
217     let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
218     q.r.f.x = 10;
219     //~^ ERROR assign to part of moved value: `q.r` [E0382]
220     use_part!(struct q.r.f);
221 }
222 
test_1111_field_partial_reinit_and_use_tuple()223 fn test_1111_field_partial_reinit_and_use_tuple() {
224     let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
225     q.r.f.0 = 10;
226     //~^ ERROR assign to part of moved value: `q.r` [E0382]
227     use_part!(tuple q.r.f);
228 }
229 
test_1200_field_void_init_and_use_struct()230 fn test_1200_field_void_init_and_use_struct() {
231     let mut q: Q<S<Void>>;
232     q.r.f.x = 10;
233     //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
234     use_part!(struct q.r.f);
235 }
236 
test_1201_field_void_init_and_use_tuple()237 fn test_1201_field_void_init_and_use_tuple() {
238     let mut q: Q<Tvoid>;
239     q.r.f.0 = 10;
240     //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
241     use_part!(tuple q.r.f);
242 }
243 
244 // See NOTE abve.
245 
246 // fn test_1210_field_void_reinit_and_use_struct() { unimplemented!() }
247 // fn test_1211_field_void_reinit_and_use_tuple() { unimplemented!() }
248 
249 // The below are some additional cases of interest that have been
250 // transcribed from other bugs based on old erroneous codegen when we
251 // encountered partial writes.
252 
issue_26996()253 fn issue_26996() {
254     let mut c = (1, "".to_owned());
255     match c {
256         c2 => {
257             c.0 = 2; //~ ERROR assign to part of moved value
258             assert_eq!(c2.0, 1);
259         }
260     }
261 }
262 
issue_27021()263 fn issue_27021() {
264     let mut c = (1, (1, "".to_owned()));
265     match c {
266         c2 => {
267             (c.1).0 = 2; //~ ERROR assign to part of moved value
268             assert_eq!((c2.1).0, 1);
269         }
270     }
271 
272     let mut c = (1, (1, (1, "".to_owned())));
273     match c.1 {
274         c2 => {
275             ((c.1).1).0 = 3; //~ ERROR assign to part of moved value
276             assert_eq!((c2.1).0, 1);
277         }
278     }
279 }
280 
main()281 fn main() {
282     test_0000_local_fully_init_and_use_struct();
283     test_0001_local_fully_init_and_use_tuple();
284     test_0010_local_fully_reinit_and_use_struct();
285     test_0011_local_fully_reinit_and_use_tuple();
286     test_0100_local_partial_init_and_use_struct();
287     test_0101_local_partial_init_and_use_tuple();
288     test_0110_local_partial_reinit_and_use_struct();
289     test_0111_local_partial_reinit_and_use_tuple();
290     test_0200_local_void_init_and_use_struct();
291     test_0201_local_void_init_and_use_tuple();
292     // test_0210_local_void_reinit_and_use_struct();
293     // test_0211_local_void_reinit_and_use_tuple();
294     test_1000_field_fully_init_and_use_struct();
295     test_1001_field_fully_init_and_use_tuple();
296     test_1010_field_fully_reinit_and_use_struct();
297     test_1011_field_fully_reinit_and_use_tuple();
298     test_1100_field_partial_init_and_use_struct();
299     test_1101_field_partial_init_and_use_tuple();
300     test_1110_field_partial_reinit_and_use_struct();
301     test_1111_field_partial_reinit_and_use_tuple();
302     test_1200_field_void_init_and_use_struct();
303     test_1201_field_void_init_and_use_tuple();
304     // test_1210_field_void_reinit_and_use_struct();
305     // test_1211_field_void_reinit_and_use_tuple();
306 
307     issue_26996();
308     issue_27021();
309 }
310