diff options
| author | Matthew Jasper <mjjasper1@gmail.com> | 2019-12-15 11:08:43 +0000 |
|---|---|---|
| committer | Matthew Jasper <mjjasper1@gmail.com> | 2019-12-19 20:28:57 +0000 |
| commit | 97219d87feee2a87bc93f7f7ef5120e526a6307d (patch) | |
| tree | 5a0e71cf775788d2b582d445a4ea23f41bda8a31 | |
| parent | c8ea4ace9213ae045123fdfeb59d1ac887656d31 (diff) | |
| download | rust-97219d87feee2a87bc93f7f7ef5120e526a6307d.tar.gz rust-97219d87feee2a87bc93f7f7ef5120e526a6307d.zip | |
Don't suppress move errors for union fields
3 files changed, 79 insertions, 9 deletions
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index fa0864e0de7..971e9a1b3b2 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -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( diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs new file mode 100644 index 00000000000..8fbf120fc1c --- /dev/null +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs @@ -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() {} diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr new file mode 100644 index 00000000000..a7cb1c9e221 --- /dev/null +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -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`. |
