about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-12-15 11:08:43 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2019-12-19 20:28:57 +0000
commit97219d87feee2a87bc93f7f7ef5120e526a6307d (patch)
tree5a0e71cf775788d2b582d445a4ea23f41bda8a31
parentc8ea4ace9213ae045123fdfeb59d1ac887656d31 (diff)
downloadrust-97219d87feee2a87bc93f7f7ef5120e526a6307d.tar.gz
rust-97219d87feee2a87bc93f7f7ef5120e526a6307d.zip
Don't suppress move errors for union fields
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs31
-rw-r--r--src/test/ui/borrowck/move-from-union-field-issue-66500.rs30
-rw-r--r--src/test/ui/borrowck/move-from-union-field-issue-66500.stderr27
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`.