Don't suppress move errors for union fields

This commit is contained in:
Matthew Jasper 2019-12-15 11:08:43 +00:00
parent c8ea4ace92
commit 97219d87fe
3 changed files with 79 additions and 9 deletions

View File

@ -103,6 +103,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
};
// The move path index of the first union that we find. Once this is
// some we stop creating child move paths, since moves from unions
// move the whole thing.
// We continue looking for other move errors though so that moving
// from `*(u.f: &_)` isn't allowed.
let mut union_path = None;
for (i, elem) in place.projection.iter().enumerate() {
let proj_base = &place.projection[..i];
let body = self.builder.body;
@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
InteriorOfTypeWithDestructor { container_ty: place_ty },
));
}
// move out of union - always move the entire union
ty::Adt(adt, _) if adt.is_union() => {
return Err(MoveError::UnionMove { path: base });
union_path.get_or_insert(base);
}
ty::Slice(_) => {
return Err(MoveError::cannot_move_out_of(
@ -155,15 +161,22 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
_ => {}
};
base = self.add_move_path(base, elem, |tcx| {
Place {
base: place.base.clone(),
projection: tcx.intern_place_elems(&place.projection[..i+1]),
}
});
if union_path.is_none() {
base = self.add_move_path(base, elem, |tcx| {
Place {
base: place.base.clone(),
projection: tcx.intern_place_elems(&place.projection[..i+1]),
}
});
}
}
Ok(base)
if let Some(base) = union_path {
// Move out of union - always move the entire union.
Err(MoveError::UnionMove { path: base })
} else {
Ok(base)
}
}
fn add_move_path(

View File

@ -0,0 +1,30 @@
// Moving from a reference/raw pointer should be an error, even when they're
// the field of a union.
#![feature(untagged_unions)]
union Pointers {
a: &'static String,
b: &'static mut String,
c: *const String,
d: *mut String,
}
unsafe fn move_ref(u: Pointers) -> String {
*u.a
//~^ ERROR cannot move out of `*u.a`
}
unsafe fn move_ref_mut(u: Pointers) -> String {
*u.b
//~^ ERROR cannot move out of `*u.b`
}
unsafe fn move_ptr(u: Pointers) -> String {
*u.c
//~^ ERROR cannot move out of `*u.c`
}
unsafe fn move_ptr_mut(u: Pointers) -> String {
*u.d
//~^ ERROR cannot move out of `*u.d`
}
fn main() {}

View File

@ -0,0 +1,27 @@
error[E0507]: cannot move out of `*u.a` which is behind a shared reference
--> $DIR/move-from-union-field-issue-66500.rs:14:5
|
LL | *u.a
| ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
--> $DIR/move-from-union-field-issue-66500.rs:18:5
|
LL | *u.b
| ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:22:5
|
LL | *u.c
| ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:26:5
|
LL | *u.d
| ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0507`.