about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-14 16:28:14 +0000
committerbors <bors@rust-lang.org>2017-04-14 16:28:14 +0000
commitba377982a3fde98a3cac02493c16dc623b02a421 (patch)
tree4ec1531021869ff497c0ef77158b3acac6b645a6
parent5637ed756632ded9e458b82a23cc1dddbb57c51f (diff)
parentad58d37c56c4121182b37fb9062c681d3d314c22 (diff)
downloadrust-ba377982a3fde98a3cac02493c16dc623b02a421.tar.gz
rust-ba377982a3fde98a3cac02493c16dc623b02a421.zip
Auto merge of #41153 - petrochenkov:umove, r=pnkfelix
Fix move checking for nested union fields

Fixes https://github.com/rust-lang/rust/issues/41126
r? @arielb1
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs30
-rw-r--r--src/test/compile-fail/union/union-borrow-move-parent-sibling.rs57
2 files changed, 72 insertions, 15 deletions
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 2047a58f8ed..5012969eef9 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -362,31 +362,31 @@ impl<'a, 'tcx> MoveData<'tcx> {
 
     /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`.
     pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                    lp: Rc<LoanPath<'tcx>>,
+                    orig_lp: Rc<LoanPath<'tcx>>,
                     id: ast::NodeId,
                     kind: MoveKind) {
-        // Moving one union field automatically moves all its fields.
-        if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
-            if let ty::TyAdt(adt_def, _) = base_lp.ty.sty {
+        // Moving one union field automatically moves all its fields. Also move siblings of
+        // all parent union fields, moves do not propagate upwards automatically.
+        let mut lp = orig_lp.clone();
+        while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind {
+            if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior))
+                    = (&base_lp.ty.sty, lp_elem) {
                 if adt_def.is_union() {
                     for field in &adt_def.struct_variant().fields {
                         let field = InteriorKind::InteriorField(mc::NamedField(field.name));
-                        let field_ty = if field == interior {
-                            lp.ty
-                        } else {
-                            tcx.types.err // Doesn't matter
-                        };
-                        let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
-                                                    LpInterior(opt_variant_id, field));
-                        let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
-                        self.add_move_helper(tcx, sibling_lp, id, kind);
+                        if field != interior {
+                            let sibling_lp_kind =
+                                LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
+                            let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
+                            self.add_move_helper(tcx, sibling_lp, id, kind);
+                        }
                     }
-                    return;
                 }
             }
+            lp = base_lp.clone();
         }
 
-        self.add_move_helper(tcx, lp.clone(), id, kind);
+        self.add_move_helper(tcx, orig_lp.clone(), id, kind);
     }
 
     fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs b/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs
new file mode 100644
index 00000000000..5f504feabb2
--- /dev/null
+++ b/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs
@@ -0,0 +1,57 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(untagged_unions)]
+#![allow(unused)]
+
+#[allow(unions_with_drop_fields)]
+union U {
+    x: ((Vec<u8>, Vec<u8>), Vec<u8>),
+    y: Box<Vec<u8>>,
+}
+
+unsafe fn parent_sibling_borrow() {
+    let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = &mut u.x.0;
+    let a = &u.y; //~ ERROR cannot borrow `u.y`
+}
+
+unsafe fn parent_sibling_move() {
+    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = u.x.0;
+    let a = u.y; //~ ERROR use of moved value: `u.y`
+}
+
+unsafe fn grandparent_sibling_borrow() {
+    let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = &mut (u.x.0).0;
+    let a = &u.y; //~ ERROR cannot borrow `u.y`
+}
+
+unsafe fn grandparent_sibling_move() {
+    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = (u.x.0).0;
+    let a = u.y; //~ ERROR use of moved value: `u.y`
+}
+
+unsafe fn deref_sibling_borrow() {
+    let mut u = U { y: Box::default() };
+    let a = &mut *u.y;
+    let a = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
+}
+
+unsafe fn deref_sibling_move() {
+    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = *u.y;
+    let a = u.x; //~ ERROR use of moved value: `u.x`
+}
+
+
+fn main() {}