Skip to content

Commit 72b9452

Browse files
matthewjasperjonas-schievink
authored andcommitted
Don't suppress move errors for union fields
1 parent 9efb92d commit 72b9452

File tree

3 files changed

+79
-9
lines changed

3 files changed

+79
-9
lines changed

src/librustc_mir/dataflow/move_paths/builder.rs

+22-9
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
103103
}
104104
};
105105

106+
// The move path index of the first union that we find. Once this is
107+
// some we stop creating child move paths, since moves from unions
108+
// move the whole thing.
109+
// We continue looking for other move errors though so that moving
110+
// from `*(u.f: &_)` isn't allowed.
111+
let mut union_path = None;
112+
106113
for (i, elem) in place.projection.iter().enumerate() {
107114
let proj_base = &place.projection[..i];
108115
let body = self.builder.body;
@@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
127134
InteriorOfTypeWithDestructor { container_ty: place_ty },
128135
));
129136
}
130-
// move out of union - always move the entire union
131137
ty::Adt(adt, _) if adt.is_union() => {
132-
return Err(MoveError::UnionMove { path: base });
138+
union_path.get_or_insert(base);
133139
}
134140
ty::Slice(_) => {
135141
return Err(MoveError::cannot_move_out_of(
@@ -155,15 +161,22 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
155161
_ => {}
156162
};
157163

158-
base = self.add_move_path(base, elem, |tcx| {
159-
Place {
160-
base: place.base.clone(),
161-
projection: tcx.intern_place_elems(&place.projection[..i+1]),
162-
}
163-
});
164+
if union_path.is_none() {
165+
base = self.add_move_path(base, elem, |tcx| {
166+
Place {
167+
base: place.base.clone(),
168+
projection: tcx.intern_place_elems(&place.projection[..i+1]),
169+
}
170+
});
171+
}
164172
}
165173

166-
Ok(base)
174+
if let Some(base) = union_path {
175+
// Move out of union - always move the entire union.
176+
Err(MoveError::UnionMove { path: base })
177+
} else {
178+
Ok(base)
179+
}
167180
}
168181

169182
fn add_move_path(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Moving from a reference/raw pointer should be an error, even when they're
2+
// the field of a union.
3+
4+
#![feature(untagged_unions)]
5+
6+
union Pointers {
7+
a: &'static String,
8+
b: &'static mut String,
9+
c: *const String,
10+
d: *mut String,
11+
}
12+
13+
unsafe fn move_ref(u: Pointers) -> String {
14+
*u.a
15+
//~^ ERROR cannot move out of `*u.a`
16+
}
17+
unsafe fn move_ref_mut(u: Pointers) -> String {
18+
*u.b
19+
//~^ ERROR cannot move out of `*u.b`
20+
}
21+
unsafe fn move_ptr(u: Pointers) -> String {
22+
*u.c
23+
//~^ ERROR cannot move out of `*u.c`
24+
}
25+
unsafe fn move_ptr_mut(u: Pointers) -> String {
26+
*u.d
27+
//~^ ERROR cannot move out of `*u.d`
28+
}
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0507]: cannot move out of `*u.a` which is behind a shared reference
2+
--> $DIR/move-from-union-field-issue-66500.rs:14:5
3+
|
4+
LL | *u.a
5+
| ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait
6+
7+
error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
8+
--> $DIR/move-from-union-field-issue-66500.rs:18:5
9+
|
10+
LL | *u.b
11+
| ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait
12+
13+
error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
14+
--> $DIR/move-from-union-field-issue-66500.rs:22:5
15+
|
16+
LL | *u.c
17+
| ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait
18+
19+
error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
20+
--> $DIR/move-from-union-field-issue-66500.rs:26:5
21+
|
22+
LL | *u.d
23+
| ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait
24+
25+
error: aborting due to 4 previous errors
26+
27+
For more information about this error, try `rustc --explain E0507`.

0 commit comments

Comments
 (0)