Skip to content

Commit b78cbf5

Browse files
committed
add empty struct tests and fix behavior for empty structs with dtors
1 parent 0e01218 commit b78cbf5

File tree

6 files changed

+121
-43
lines changed

6 files changed

+121
-43
lines changed

compiler/rustc_borrowck/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,7 +2093,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
20932093
let path = &self.move_data.move_paths[mpi];
20942094

20952095
let field_count = match path.place.ty(self.body(), tcx).ty.kind() {
2096-
ty::Adt(adt, _) if adt.is_struct() => {
2096+
ty::Adt(adt, _) if adt.is_struct() && !adt.has_dtor(tcx) => {
20972097
let variant = adt.non_enum_variant();
20982098

20992099
if variant.field_list_has_applicable_non_exhaustive() {
@@ -2107,8 +2107,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
21072107
_ => return true,
21082108
};
21092109

2110-
// FIXME: destructors?
2111-
21122110
// A structurally initialized type is "uninit" but all of it's fields are init.
21132111
// This means all of it's fields must have MovePaths
21142112
// because fields that are never written to will not have MovePaths.

tests/ui/borrowck/structural_init.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ struct R<F> {
5252
impl<F> Q<F> { fn new(f: F) -> Self { Q { v: 0, r: R::new(f) } } }
5353
impl<F> R<F> { fn new(f: F) -> Self { R { w: 0, f } } }
5454

55+
struct Empty;
56+
5557
// Axes to cover:
5658
// * local/field: Is the structure in a local or a field
5759
// * fully/partial/void: Are we fully initializing it before using any part?
@@ -269,6 +271,19 @@ fn issue_27021() {
269271
}
270272
}
271273

274+
// Strange case discovered during implementation.
275+
// FIXME: not decided if this should compile or not.
276+
fn test_empty_struct() {
277+
let e: Empty;
278+
drop(e); //[stable]~ ERROR used binding `e` isn't initialized [E0381]
279+
}
280+
281+
#[expect(dropping_copy_types)]
282+
fn test_empty_tuple() {
283+
let t: ();
284+
drop(t); //[stable]~ ERROR used binding `t` isn't initialized [E0381]
285+
}
286+
272287
fn main() {
273288
test_0000_local_fully_init_and_use_struct();
274289
test_0001_local_fully_init_and_use_tuple();
@@ -297,4 +312,7 @@ fn main() {
297312

298313
issue_26996();
299314
issue_27021();
315+
316+
test_empty_struct();
317+
test_empty_tuple();
300318
}

tests/ui/borrowck/structural_init.stable.stderr

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0381]: partially assigned binding `s` isn't fully initialized
2-
--> $DIR/structural_init.rs:104:5
2+
--> $DIR/structural_init.rs:102:5
33
|
44
LL | let s: S<B>;
55
| - binding declared here but left uninitialized
@@ -9,7 +9,7 @@ LL | s.x = 10; s.y = Box::new(20);
99
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
1010

1111
error[E0381]: partially assigned binding `t` isn't fully initialized
12-
--> $DIR/structural_init.rs:110:5
12+
--> $DIR/structural_init.rs:108:5
1313
|
1414
LL | let t: T;
1515
| - binding declared here but left uninitialized
@@ -19,7 +19,7 @@ LL | t.0 = 10; t.1 = Box::new(20);
1919
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
2020

2121
error[E0382]: assign to part of moved value: `s`
22-
--> $DIR/structural_init.rs:116:5
22+
--> $DIR/structural_init.rs:114:5
2323
|
2424
LL | let mut s: S<B> = S::new(); drop(s);
2525
| ----- - value moved here
@@ -29,7 +29,7 @@ LL | s.x = 10; s.y = Box::new(20);
2929
| ^^^^^^^^ value partially assigned here after move
3030
|
3131
note: if `S<Box<u32>>` implemented `Clone`, you could clone the value
32-
--> $DIR/structural_init.rs:20:1
32+
--> $DIR/structural_init.rs:16:1
3333
|
3434
LL | struct S<Y> {
3535
| ^^^^^^^^^^^ consider implementing `Clone` for this type
@@ -38,7 +38,7 @@ LL | let mut s: S<B> = S::new(); drop(s);
3838
| - you could clone this value
3939

4040
error[E0382]: assign to part of moved value: `t`
41-
--> $DIR/structural_init.rs:123:5
41+
--> $DIR/structural_init.rs:121:5
4242
|
4343
LL | let mut t: T = (0, Box::new(0)); drop(t);
4444
| ----- - value moved here
@@ -53,7 +53,7 @@ LL | let mut t: T = (0, Box::new(0)); drop(t.clone());
5353
| ++++++++
5454

5555
error[E0381]: partially assigned binding `s` isn't fully initialized
56-
--> $DIR/structural_init.rs:130:5
56+
--> $DIR/structural_init.rs:128:5
5757
|
5858
LL | let s: S<B>;
5959
| - binding declared here but left uninitialized
@@ -63,7 +63,7 @@ LL | s.x = 10;
6363
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
6464

6565
error[E0381]: partially assigned binding `t` isn't fully initialized
66-
--> $DIR/structural_init.rs:136:5
66+
--> $DIR/structural_init.rs:134:5
6767
|
6868
LL | let t: T;
6969
| - binding declared here but left uninitialized
@@ -73,7 +73,7 @@ LL | t.0 = 10;
7373
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
7474

7575
error[E0382]: assign to part of moved value: `s`
76-
--> $DIR/structural_init.rs:142:5
76+
--> $DIR/structural_init.rs:140:5
7777
|
7878
LL | let mut s: S<B> = S::new(); drop(s);
7979
| ----- - value moved here
@@ -83,7 +83,7 @@ LL | s.x = 10;
8383
| ^^^^^^^^ value partially assigned here after move
8484
|
8585
note: if `S<Box<u32>>` implemented `Clone`, you could clone the value
86-
--> $DIR/structural_init.rs:20:1
86+
--> $DIR/structural_init.rs:16:1
8787
|
8888
LL | struct S<Y> {
8989
| ^^^^^^^^^^^ consider implementing `Clone` for this type
@@ -92,7 +92,7 @@ LL | let mut s: S<B> = S::new(); drop(s);
9292
| - you could clone this value
9393

9494
error[E0382]: assign to part of moved value: `t`
95-
--> $DIR/structural_init.rs:149:5
95+
--> $DIR/structural_init.rs:147:5
9696
|
9797
LL | let mut t: T = (0, Box::new(0)); drop(t);
9898
| ----- - value moved here
@@ -107,7 +107,7 @@ LL | let mut t: T = (0, Box::new(0)); drop(t.clone());
107107
| ++++++++
108108

109109
error[E0381]: partially assigned binding `s` isn't fully initialized
110-
--> $DIR/structural_init.rs:156:5
110+
--> $DIR/structural_init.rs:154:5
111111
|
112112
LL | let s: S<Void>;
113113
| - binding declared here but left uninitialized
@@ -117,7 +117,7 @@ LL | s.x = 10;
117117
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
118118

119119
error[E0381]: partially assigned binding `t` isn't fully initialized
120-
--> $DIR/structural_init.rs:162:5
120+
--> $DIR/structural_init.rs:160:5
121121
|
122122
LL | let t: Tvoid;
123123
| - binding declared here but left uninitialized
@@ -127,7 +127,7 @@ LL | t.0 = 10;
127127
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
128128

129129
error[E0381]: partially assigned binding `q` isn't fully initialized
130-
--> $DIR/structural_init.rs:177:5
130+
--> $DIR/structural_init.rs:175:5
131131
|
132132
LL | let q: Q<S<B>>;
133133
| - binding declared here but left uninitialized
@@ -137,7 +137,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20);
137137
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
138138

139139
error[E0381]: partially assigned binding `q` isn't fully initialized
140-
--> $DIR/structural_init.rs:183:5
140+
--> $DIR/structural_init.rs:181:5
141141
|
142142
LL | let q: Q<T>;
143143
| - binding declared here but left uninitialized
@@ -147,7 +147,7 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20);
147147
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
148148

149149
error[E0382]: assign to part of moved value: `q.r`
150-
--> $DIR/structural_init.rs:189:5
150+
--> $DIR/structural_init.rs:187:5
151151
|
152152
LL | let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
153153
| --- value moved here
@@ -157,7 +157,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20);
157157
= note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait
158158

159159
error[E0382]: assign to part of moved value: `q.r`
160-
--> $DIR/structural_init.rs:196:5
160+
--> $DIR/structural_init.rs:194:5
161161
|
162162
LL | let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
163163
| --- value moved here
@@ -167,7 +167,7 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20);
167167
= note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait
168168

169169
error[E0381]: partially assigned binding `q` isn't fully initialized
170-
--> $DIR/structural_init.rs:203:5
170+
--> $DIR/structural_init.rs:201:5
171171
|
172172
LL | let q: Q<S<B>>;
173173
| - binding declared here but left uninitialized
@@ -177,7 +177,7 @@ LL | q.r.f.x = 10;
177177
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
178178

179179
error[E0381]: partially assigned binding `q` isn't fully initialized
180-
--> $DIR/structural_init.rs:209:5
180+
--> $DIR/structural_init.rs:207:5
181181
|
182182
LL | let q: Q<T>;
183183
| - binding declared here but left uninitialized
@@ -187,7 +187,7 @@ LL | q.r.f.0 = 10;
187187
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
188188

189189
error[E0382]: assign to part of moved value: `q.r`
190-
--> $DIR/structural_init.rs:215:5
190+
--> $DIR/structural_init.rs:213:5
191191
|
192192
LL | let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
193193
| --- value moved here
@@ -197,7 +197,7 @@ LL | q.r.f.x = 10;
197197
= note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait
198198

199199
error[E0382]: assign to part of moved value: `q.r`
200-
--> $DIR/structural_init.rs:222:5
200+
--> $DIR/structural_init.rs:220:5
201201
|
202202
LL | let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
203203
| --- value moved here
@@ -207,7 +207,7 @@ LL | q.r.f.0 = 10;
207207
= note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait
208208

209209
error[E0381]: partially assigned binding `q` isn't fully initialized
210-
--> $DIR/structural_init.rs:229:5
210+
--> $DIR/structural_init.rs:227:5
211211
|
212212
LL | let q: Q<S<Void>>;
213213
| - binding declared here but left uninitialized
@@ -217,7 +217,7 @@ LL | q.r.f.x = 10;
217217
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
218218

219219
error[E0381]: partially assigned binding `q` isn't fully initialized
220-
--> $DIR/structural_init.rs:235:5
220+
--> $DIR/structural_init.rs:233:5
221221
|
222222
LL | let q: Q<Tvoid>;
223223
| - binding declared here but left uninitialized
@@ -227,7 +227,7 @@ LL | q.r.f.0 = 10;
227227
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
228228

229229
error[E0382]: assign to part of moved value: `c`
230-
--> $DIR/structural_init.rs:252:13
230+
--> $DIR/structural_init.rs:250:13
231231
|
232232
LL | let mut c = (1, "".to_owned());
233233
| ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait
@@ -243,7 +243,7 @@ LL | ref c2 => {
243243
| +++
244244

245245
error[E0382]: assign to part of moved value: `c`
246-
--> $DIR/structural_init.rs:262:13
246+
--> $DIR/structural_init.rs:260:13
247247
|
248248
LL | let mut c = (1, (1, "".to_owned()));
249249
| ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait
@@ -259,7 +259,7 @@ LL | ref c2 => {
259259
| +++
260260

261261
error[E0382]: assign to part of moved value: `c.1`
262-
--> $DIR/structural_init.rs:270:13
262+
--> $DIR/structural_init.rs:268:13
263263
|
264264
LL | c2 => {
265265
| -- value moved here
@@ -272,7 +272,33 @@ help: borrow this binding in the pattern to avoid moving the value
272272
LL | ref c2 => {
273273
| +++
274274

275-
error: aborting due to 23 previous errors
275+
error[E0381]: used binding `e` isn't initialized
276+
--> $DIR/structural_init.rs:278:10
277+
|
278+
LL | let e: Empty;
279+
| - binding declared here but left uninitialized
280+
LL | drop(e);
281+
| ^ `e` used here but it isn't initialized
282+
|
283+
help: consider assigning a value
284+
|
285+
LL | let e: Empty = /* value */;
286+
| +++++++++++++
287+
288+
error[E0381]: used binding `t` isn't initialized
289+
--> $DIR/structural_init.rs:284:10
290+
|
291+
LL | let t: ();
292+
| - binding declared here but left uninitialized
293+
LL | drop(t);
294+
| ^ `t` used here but it isn't initialized
295+
|
296+
help: consider assigning a value
297+
|
298+
LL | let t: () = ();
299+
| ++++
300+
301+
error: aborting due to 25 previous errors
276302

277303
Some errors have detailed explanations: E0381, E0382.
278304
For more information about an error, try `rustc --explain E0381`.

tests/ui/borrowck/structural_init_invalid.feature.stderr

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0381]: assigned binding `d` isn't fully initialized
2-
--> $DIR/structural_init_invalid.rs:31:5
2+
--> $DIR/structural_init_invalid.rs:33:5
33
|
44
LL | let d: D;
55
| - binding declared here but left uninitialized
@@ -9,7 +9,7 @@ LL | d.x = 10;
99
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
1010

1111
error[E0381]: assigned binding `d` isn't fully initialized
12-
--> $DIR/structural_init_invalid.rs:36:5
12+
--> $DIR/structural_init_invalid.rs:38:5
1313
|
1414
LL | let mut d: D;
1515
| ----- binding declared here but left uninitialized
@@ -19,7 +19,7 @@ LL | d.x = 10;
1919
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
2020

2121
error[E0382]: assign of moved value: `d`
22-
--> $DIR/structural_init_invalid.rs:42:5
22+
--> $DIR/structural_init_invalid.rs:44:5
2323
|
2424
LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
2525
| ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
@@ -29,7 +29,7 @@ LL | d.x = 10;
2929
| ^^^^^^^^ value assigned here after move
3030

3131
error[E0381]: assigned binding `d` isn't fully initialized
32-
--> $DIR/structural_init_invalid.rs:48:5
32+
--> $DIR/structural_init_invalid.rs:50:5
3333
|
3434
LL | let d: D;
3535
| - binding declared here but left uninitialized
@@ -39,7 +39,7 @@ LL | d.s.y = 20;
3939
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
4040

4141
error[E0381]: assigned binding `d` isn't fully initialized
42-
--> $DIR/structural_init_invalid.rs:53:5
42+
--> $DIR/structural_init_invalid.rs:55:5
4343
|
4444
LL | let mut d: D;
4545
| ----- binding declared here but left uninitialized
@@ -49,7 +49,7 @@ LL | d.s.y = 20;
4949
= help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
5050

5151
error[E0382]: assign of moved value: `d`
52-
--> $DIR/structural_init_invalid.rs:59:5
52+
--> $DIR/structural_init_invalid.rs:61:5
5353
|
5454
LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} };
5555
| ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
@@ -58,7 +58,20 @@ LL | drop(d);
5858
LL | d.s.y = 20;
5959
| ^^^^^^^^^^ value assigned here after move
6060

61-
error: aborting due to 6 previous errors
61+
error[E0381]: used binding `e` isn't initialized
62+
--> $DIR/structural_init_invalid.rs:69:10
63+
|
64+
LL | let e: EmptyWithDrop;
65+
| - binding declared here but left uninitialized
66+
LL | drop(e);
67+
| ^ `e` used here but it isn't initialized
68+
|
69+
help: consider assigning a value
70+
|
71+
LL | let e: EmptyWithDrop = /* value */;
72+
| +++++++++++++
73+
74+
error: aborting due to 7 previous errors
6275

6376
Some errors have detailed explanations: E0381, E0382.
6477
For more information about an error, try `rustc --explain E0381`.

0 commit comments

Comments
 (0)