diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 50169ca64307b..3f48051029d9d 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -744,7 +744,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { self.check_if_assigned_path_is_moved(id, span, use_kind, lp_base); } - LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { // In the case where the owner implements drop, then @@ -770,7 +770,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { self.check_if_assigned_path_is_moved(id, span, use_kind, lp_base); } - LpExtend(ref lp_base, _, LpInterior(InteriorElement(..))) | + LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) | LpExtend(ref lp_base, _, LpDeref(_)) => { // assigning to `P[i]` requires `P` is initialized // assigning to `(*P)` requires `P` is initialized diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 1639fcf77a661..c5e2b69683b10 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -379,7 +379,7 @@ fn add_fragment_siblings<'tcx>(this: &MoveData<'tcx>, // bind. // // Anyway, for now: LV[j] is not tracked precisely - LpExtend(_, _, LpInterior(InteriorElement(..))) => { + LpExtend(_, _, LpInterior(_, InteriorElement(..))) => { let mp = this.move_path(tcx, lp.clone()); gathered_fragments.push(AllButOneFrom(mp)); } @@ -387,7 +387,7 @@ fn add_fragment_siblings<'tcx>(this: &MoveData<'tcx>, // field access LV.x and tuple access LV#k are the cases // we are interested in LpExtend(ref loan_parent, mc, - LpInterior(InteriorField(ref field_name))) => { + LpInterior(_, InteriorField(ref field_name))) => { let enum_variant_info = match loan_parent.kind { LpDowncast(ref loan_parent_2, variant_def_id) => Some((variant_def_id, loan_parent_2.clone())), @@ -516,7 +516,7 @@ fn add_fragment_sibling_core<'tcx>(this: &MoveData<'tcx>, LpVar(..) | LpUpvar(..) | LpExtend(..) => enum_variant_did, }; - let loan_path_elem = LpInterior(InteriorField(new_field_name)); + let loan_path_elem = LpInterior(opt_variant_did, InteriorField(new_field_name)); let new_lp_type = match new_field_name { mc::NamedField(ast_name) => tcx.named_element_ty(parent.to_type(), ast_name, opt_variant_did), diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index e7ce93972633b..cb75180b47466 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -97,8 +97,12 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { // Overwriting the base would not change the type of // the memory, so no additional restrictions are // needed. + let opt_variant_id = match cmt_base.cat { + Categorization::Downcast(_, variant_id) => Some(variant_id), + _ => None + }; let result = self.restrict(cmt_base); - self.extend(result, &cmt, LpInterior(i.cleaned())) + self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned())) } Categorization::StaticItem => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index b727f10d276ac..64bbf49e3a8e0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -377,10 +377,18 @@ impl ToInteriorKind for mc::InteriorKind { } } +// This can be: +// - a pointer dereference (`*LV` in README.md) +// - a field reference, with an optional definition of the containing +// enum variant (`LV.f` in README.md) +// `DefId` is present when the field is part of struct that is in +// a variant of an enum. For instance in: +// `enum E { X { foo: u32 }, Y { foo: u32 }}` +// each `foo` is qualified by the definitition id of the variant (`X` or `Y`). #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum LoanPathElem { - LpDeref(mc::PointerKind), // `*LV` in README.md - LpInterior(InteriorKind), // `LV.f` in README.md + LpDeref(mc::PointerKind), + LpInterior(Option, InteriorKind), } pub fn closure_to_block(closure_id: ast::NodeId, @@ -413,8 +421,9 @@ impl<'tcx> LoanPath<'tcx> { fn has_fork(&self, other: &LoanPath<'tcx>) -> bool { match (&self.kind, &other.kind) { - (&LpExtend(ref base, _, LpInterior(id)), &LpExtend(ref base2, _, LpInterior(id2))) => - if id == id2 { + (&LpExtend(ref base, _, LpInterior(opt_variant_id, id)), + &LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) => + if id == id2 && opt_variant_id == opt_variant_id2 { base.has_fork(&**base2) } else { true @@ -428,23 +437,23 @@ impl<'tcx> LoanPath<'tcx> { fn depth(&self) -> usize { match self.kind { LpExtend(ref base, _, LpDeref(_)) => base.depth(), - LpExtend(ref base, _, LpInterior(_)) => base.depth() + 1, + LpExtend(ref base, _, LpInterior(_, _)) => base.depth() + 1, _ => 0, } } fn common(&self, other: &LoanPath<'tcx>) -> Option> { match (&self.kind, &other.kind) { - (&LpExtend(ref base, a, LpInterior(id)), - &LpExtend(ref base2, _, LpInterior(id2))) => { - if id == id2 { + (&LpExtend(ref base, a, LpInterior(opt_variant_id, id)), + &LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) => { + if id == id2 && opt_variant_id == opt_variant_id2 { base.common(&**base2).map(|x| { let xd = x.depth(); if base.depth() == xd && base2.depth() == xd { assert_eq!(base.ty, base2.ty); assert_eq!(self.ty, other.ty); LoanPath { - kind: LpExtend(Rc::new(x), a, LpInterior(id)), + kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)), ty: self.ty, } } else { @@ -509,7 +518,11 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { Categorization::Interior(ref cmt_base, ik) => { opt_loan_path(cmt_base).map(|lp| { - new_lp(LpExtend(lp, cmt.mutbl, LpInterior(ik.cleaned()))) + let opt_variant_id = match cmt_base.cat { + Categorization::Downcast(_, did) => Some(did), + _ => None + }; + new_lp(LpExtend(lp, cmt.mutbl, LpInterior(opt_variant_id, ik.cleaned()))) }) } @@ -1068,7 +1081,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } - LpExtend(ref lp_base, _, LpInterior(InteriorField(fname))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => { self.append_autoderefd_loan_path_to_string(&**lp_base, out); match fname { mc::NamedField(fname) => { @@ -1082,7 +1095,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - LpExtend(ref lp_base, _, LpInterior(InteriorElement(..))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => { self.append_autoderefd_loan_path_to_string(&**lp_base, out); out.push_str("[..]"); } @@ -1210,7 +1223,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { write!(f, "{:?}.*", lp) } - LpExtend(ref lp, _, LpInterior(ref interior)) => { + LpExtend(ref lp, _, LpInterior(_, ref interior)) => { write!(f, "{:?}.{:?}", lp, interior) } } @@ -1242,7 +1255,7 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { write!(f, "{}.*", lp) } - LpExtend(ref lp, _, LpInterior(ref interior)) => { + LpExtend(ref lp, _, LpInterior(_, ref interior)) => { write!(f, "{}.{:?}", lp, interior) } } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 3ac6e7c5d69eb..62404a73ad3be 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -195,7 +195,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool { LpVar(_) | LpUpvar(_) => { true } - LpExtend(_, _, LpInterior(InteriorKind::InteriorElement(..))) => { + LpExtend(_, _, LpInterior(_, InteriorKind::InteriorElement(..))) => { // Paths involving element accesses a[i] do not refer to a unique // location, as there is no accurate tracking of the indices. // diff --git a/src/test/run-pass/issue-27889.rs b/src/test/run-pass/issue-27889.rs new file mode 100644 index 0000000000000..3f7d0400c884e --- /dev/null +++ b/src/test/run-pass/issue-27889.rs @@ -0,0 +1,31 @@ +// Copyright 2015 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. + +// Test that a field can have the same name in different variants +// of an enum +// FIXME #27889 + +pub enum Foo { + X { foo: u32 }, + Y { foo: u32 } +} + +pub fn foo(mut x: Foo) { + let mut y = None; + let mut z = None; + if let Foo::X { ref foo } = x { + z = Some(foo); + } + if let Foo::Y { ref mut foo } = x { + y = Some(foo); + } +} + +fn main() {}