From 97219d87feee2a87bc93f7f7ef5120e526a6307d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 15 Dec 2019 11:08:43 +0000 Subject: [PATCH] Don't suppress move errors for union fields --- .../dataflow/move_paths/builder.rs | 31 +++++++++++++------ .../move-from-union-field-issue-66500.rs | 30 ++++++++++++++++++ .../move-from-union-field-issue-66500.stderr | 27 ++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/borrowck/move-from-union-field-issue-66500.rs create mode 100644 src/test/ui/borrowck/move-from-union-field-issue-66500.stderr diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index fa0864e0de760..971e9a1b3b281 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 0000000000000..8fbf120fc1c78 --- /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 0000000000000..a7cb1c9e22135 --- /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`.