diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 0692d284d7c1..5a4f2157298b 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -171,7 +171,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { for (r, vid) in seeds { // While all things transitively reachable in the graph // from the variable (`'0` in the example above). - let seed_index = NodeIndex(vid.index as usize); + let seed_index = NodeIndex(vid.index() as usize); for succ_index in graph.depth_traverse(seed_index, OUTGOING) { let succ_index = succ_index.0; @@ -512,16 +512,16 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { match *constraint { Constraint::VarSubVar(a_id, b_id) => { graph.add_edge( - NodeIndex(a_id.index as usize), - NodeIndex(b_id.index as usize), + NodeIndex(a_id.index() as usize), + NodeIndex(b_id.index() as usize), *constraint, ); } Constraint::RegSubVar(_, b_id) => { - graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint); + graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint); } Constraint::VarSubReg(a_id, _) => { - graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint); + graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint); } Constraint::RegSubReg(..) => { // this would be an edge from `dummy_source` to @@ -630,9 +630,9 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { let node_idx = state.stack.pop().unwrap(); // check whether we've visited this node on some previous walk - if dup_vec[node_idx.index as usize] == u32::MAX { - dup_vec[node_idx.index as usize] = orig_node_idx.index; - } else if dup_vec[node_idx.index as usize] != orig_node_idx.index { + if dup_vec[node_idx.index() as usize] == u32::MAX { + dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32; + } else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 { state.dup_found = true; } @@ -659,7 +659,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { ) { debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); - let source_node_index = NodeIndex(source_vid.index as usize); + let source_node_index = NodeIndex(source_vid.index() as usize); for (_, edge) in graph.adjacent_edges(source_node_index, dir) { match edge.data { Constraint::VarSubVar(from_vid, to_vid) => { diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 096037ebe880..72740dd40be2 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -16,7 +16,7 @@ use self::CombineMapType::*; use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; use super::unify_key; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unify::{self, UnificationTable}; use ty::{self, Ty, TyCtxt}; @@ -404,7 +404,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { } AddVar(vid) => { self.var_origins.pop().unwrap(); - assert_eq!(self.var_origins.len(), vid.index as usize); + assert_eq!(self.var_origins.len(), vid.index() as usize); } AddConstraint(ref constraint) => { self.data.constraints.remove(constraint); diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index d7e3a53ff25c..99b11794cc5b 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -33,7 +33,7 @@ pub struct RegionVidKey { impl Combine for RegionVidKey { fn combine(&self, other: &RegionVidKey) -> RegionVidKey { - let min_vid = if self.min_vid.index < other.min_vid.index { + let min_vid = if self.min_vid.index() < other.min_vid.index() { self.min_vid } else { other.min_vid @@ -45,8 +45,8 @@ impl Combine for RegionVidKey { impl UnifyKey for ty::RegionVid { type Value = RegionVidKey; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } } + fn index(&self) -> u32 { self.0 } + fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid(i) } fn tag(_: Option) -> &'static str { "RegionVid" } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 355fb570c000..94e8033ed163 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1375,10 +1375,14 @@ pub enum AggregateKind<'tcx> { /// The type is of the element Array(Ty<'tcx>), Tuple, - /// The second field is variant number (discriminant), it's equal to 0 - /// for struct and union expressions. The fourth field is active field - /// number and is present only for union expressions. + + /// The second field is variant number (discriminant), it's equal + /// to 0 for struct and union expressions. The fourth field is + /// active field number and is present only for union expressions + /// -- e.g. for a union expression `SomeUnion { c: .. }`, the + /// active field index would identity the field `c` Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option), + Closure(DefId, ClosureSubsts<'tcx>), Generator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>), } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7406fbf82089..9d393296c5b2 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -998,22 +998,11 @@ pub struct FloatVid { pub index: u32, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy, PartialOrd, Ord)] -pub struct RegionVid { - pub index: u32, -} - -// FIXME: We could convert this to use `newtype_index!` -impl Idx for RegionVid { - fn new(value: usize) -> Self { - assert!(value < ::std::u32::MAX as usize); - RegionVid { index: value as u32 } - } - - fn index(self) -> usize { - self.index as usize - } -} +newtype_index!(RegionVid + { + pub idx + DEBUG_FORMAT = custom, + }); #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)] pub struct SkolemizedRegionVid { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2c3a32b2d159..9ff3d73f5c40 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -726,7 +726,7 @@ define_print! { } } ty::ReVar(region_vid) if cx.identify_regions => { - write!(f, "'{}rv", region_vid.index) + write!(f, "'{}rv", region_vid.index()) } ty::ReScope(_) | ty::ReVar(_) | @@ -850,7 +850,7 @@ impl fmt::Debug for ty::FloatVid { impl fmt::Debug for ty::RegionVid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "'_#{}r", self.index) + write!(f, "'_#{}r", self.index()) } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index d31f3812e9a1..15c68954230b 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -825,10 +825,16 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, -> Mir<'tcx> { let tcx = infcx.tcx; + let gcx = tcx.global_tcx(); let def_id = tcx.hir.local_def_id(ctor_id); - let sig = tcx.no_late_bound_regions(&tcx.fn_sig(def_id)) + let sig = gcx.no_late_bound_regions(&gcx.fn_sig(def_id)) .expect("LBR in ADT constructor signature"); - let sig = tcx.erase_regions(&sig); + let sig = gcx.erase_regions(&sig); + let param_env = gcx.param_env(def_id); + + // Normalize the sig now that we have liberated the late-bound + // regions. + let sig = gcx.normalize_associated_type_in_env(&sig, param_env); let (adt_def, substs) = match sig.output().sty { ty::TyAdt(adt_def, substs) => (adt_def, substs), diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index cc6b70209031..ade5cf8b70c2 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -549,6 +549,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { terr ); } + self.check_rvalue(mir, rv, location); } StatementKind::SetDiscriminant { ref lvalue, @@ -1011,6 +1012,111 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } + fn aggregate_field_ty( + &mut self, + ak: &Box>, + field_index: usize, + location: Location, + ) -> Result, FieldAccessError> { + let tcx = self.tcx(); + + match **ak { + AggregateKind::Adt(def, variant_index, substs, active_field_index) => { + let variant = &def.variants[variant_index]; + let adj_field_index = active_field_index.unwrap_or(field_index); + if let Some(field) = variant.fields.get(adj_field_index) { + Ok(self.normalize(&field.ty(tcx, substs), location)) + } else { + Err(FieldAccessError::OutOfRange { + field_count: variant.fields.len(), + }) + } + } + AggregateKind::Closure(def_id, substs) => { + match substs.upvar_tys(def_id, tcx).nth(field_index) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.upvar_tys(def_id, tcx).count(), + }), + } + } + AggregateKind::Generator(def_id, substs, _) => { + if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) { + Ok(ty) + } else { + match substs.field_tys(def_id, tcx).nth(field_index) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.field_tys(def_id, tcx).count() + 1, + }), + } + } + } + AggregateKind::Array(ty) => { + Ok(ty) + } + AggregateKind::Tuple => { + unreachable!("This should have been covered in check_rvalues"); + } + } + } + + fn check_rvalue(&mut self, mir: &Mir<'tcx>, rv: &Rvalue<'tcx>, location: Location) { + let tcx = self.tcx(); + match rv { + Rvalue::Aggregate(ak, ops) => { + match **ak { + // tuple rvalue field type is always the type of the op. Nothing to check here. + AggregateKind::Tuple => {} + _ => { + for (i, op) in ops.iter().enumerate() { + let field_ty = match self.aggregate_field_ty(ak, i, location) { + Ok(field_ty) => field_ty, + Err(FieldAccessError::OutOfRange { field_count }) => { + span_mirbug!( + self, + rv, + "accessed field #{} but variant only has {}", + i, + field_count + ); + continue; + } + }; + let op_ty = op.ty(mir, tcx); + if let Err(terr) = self.sub_types( + op_ty, + field_ty, + location.at_successor_within_block(), + ) + { + span_mirbug!( + self, + rv, + "{:?} is not a subtype of {:?}: {:?}", + op_ty, + field_ty, + terr + ); + } + } + } + } + } + // FIXME: These other cases have to be implemented in future PRs + Rvalue::Use(..) | + Rvalue::Repeat(..) | + Rvalue::Ref(..) | + Rvalue::Len(..) | + Rvalue::Cast(..) | + Rvalue::BinaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::UnaryOp(..) | + Rvalue::Discriminant(..) | + Rvalue::NullaryOp(..) => {} + } + } + fn typeck_mir(&mut self, mir: &Mir<'tcx>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); diff --git a/src/test/compile-fail/nll/reference-carried-through-struct-field.rs b/src/test/compile-fail/nll/reference-carried-through-struct-field.rs new file mode 100644 index 000000000000..afde25408294 --- /dev/null +++ b/src/test/compile-fail/nll/reference-carried-through-struct-field.rs @@ -0,0 +1,27 @@ +// 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. +//revisions: ast mir +//[mir] compile-flags: -Z emit-end-regions -Z borrowck-mir -Z nll + +#![allow(unused_assignments)] + +struct Wrap<'a> { w: &'a mut u32 } + +fn foo() { + let mut x = 22; + let wrapper = Wrap { w: &mut x }; + x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506] + //[mir]~^ ERROR cannot assign to `x` because it is borrowed (Ast) [E0506] + //[mir]~^^ ERROR cannot assign to `x` because it is borrowed (Mir) [E0506] + //[mir]~^^^ ERROR cannot use `x` because it was mutably borrowed (Mir) [E0503] + *wrapper.w += 1; +} + +fn main() { } \ No newline at end of file