Skip to content

Commit ba37798

Browse files
committed
Auto merge of #41153 - petrochenkov:umove, r=pnkfelix
Fix move checking for nested union fields Fixes #41126 r? @arielb1
2 parents 5637ed7 + ad58d37 commit ba37798

File tree

2 files changed

+72
-15
lines changed

2 files changed

+72
-15
lines changed

src/librustc_borrowck/borrowck/move_data.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -362,31 +362,31 @@ impl<'a, 'tcx> MoveData<'tcx> {
362362

363363
/// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`.
364364
pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
365-
lp: Rc<LoanPath<'tcx>>,
365+
orig_lp: Rc<LoanPath<'tcx>>,
366366
id: ast::NodeId,
367367
kind: MoveKind) {
368-
// Moving one union field automatically moves all its fields.
369-
if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
370-
if let ty::TyAdt(adt_def, _) = base_lp.ty.sty {
368+
// Moving one union field automatically moves all its fields. Also move siblings of
369+
// all parent union fields, moves do not propagate upwards automatically.
370+
let mut lp = orig_lp.clone();
371+
while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind {
372+
if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior))
373+
= (&base_lp.ty.sty, lp_elem) {
371374
if adt_def.is_union() {
372375
for field in &adt_def.struct_variant().fields {
373376
let field = InteriorKind::InteriorField(mc::NamedField(field.name));
374-
let field_ty = if field == interior {
375-
lp.ty
376-
} else {
377-
tcx.types.err // Doesn't matter
378-
};
379-
let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
380-
LpInterior(opt_variant_id, field));
381-
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
382-
self.add_move_helper(tcx, sibling_lp, id, kind);
377+
if field != interior {
378+
let sibling_lp_kind =
379+
LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
380+
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
381+
self.add_move_helper(tcx, sibling_lp, id, kind);
382+
}
383383
}
384-
return;
385384
}
386385
}
386+
lp = base_lp.clone();
387387
}
388388

389-
self.add_move_helper(tcx, lp.clone(), id, kind);
389+
self.add_move_helper(tcx, orig_lp.clone(), id, kind);
390390
}
391391

392392
fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(untagged_unions)]
12+
#![allow(unused)]
13+
14+
#[allow(unions_with_drop_fields)]
15+
union U {
16+
x: ((Vec<u8>, Vec<u8>), Vec<u8>),
17+
y: Box<Vec<u8>>,
18+
}
19+
20+
unsafe fn parent_sibling_borrow() {
21+
let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
22+
let a = &mut u.x.0;
23+
let a = &u.y; //~ ERROR cannot borrow `u.y`
24+
}
25+
26+
unsafe fn parent_sibling_move() {
27+
let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
28+
let a = u.x.0;
29+
let a = u.y; //~ ERROR use of moved value: `u.y`
30+
}
31+
32+
unsafe fn grandparent_sibling_borrow() {
33+
let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
34+
let a = &mut (u.x.0).0;
35+
let a = &u.y; //~ ERROR cannot borrow `u.y`
36+
}
37+
38+
unsafe fn grandparent_sibling_move() {
39+
let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
40+
let a = (u.x.0).0;
41+
let a = u.y; //~ ERROR use of moved value: `u.y`
42+
}
43+
44+
unsafe fn deref_sibling_borrow() {
45+
let mut u = U { y: Box::default() };
46+
let a = &mut *u.y;
47+
let a = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
48+
}
49+
50+
unsafe fn deref_sibling_move() {
51+
let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
52+
let a = *u.y;
53+
let a = u.x; //~ ERROR use of moved value: `u.x`
54+
}
55+
56+
57+
fn main() {}

0 commit comments

Comments
 (0)