diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 2047a58f8ed85..5012969eef905 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>, + orig_lp: Rc>, 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 0000000000000..5f504feabb266 --- /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 or the MIT license +// , 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, Vec), Vec), + y: Box>, +} + +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() {}