diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index b2ff36cb87c7..c109020496cf 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -228,7 +228,7 @@ impl<'tcx> Mir<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable { + if self.local_decls[local].is_user_variable.is_some() { None } else { Some(local) @@ -241,7 +241,7 @@ impl<'tcx> Mir<'tcx> { pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable { + if self.local_decls[local].is_user_variable.is_some() { Some(local) } else { None @@ -255,7 +255,7 @@ impl<'tcx> Mir<'tcx> { (1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; - if (decl.is_user_variable || index < self.arg_count + 1) + if (decl.is_user_variable.is_some() || index < self.arg_count + 1) && decl.mutability == Mutability::Mut { Some(local) @@ -351,7 +351,7 @@ impl<'tcx> IndexMut for Mir<'tcx> { } } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum ClearCrossCrate { Clear, Set(T) @@ -382,6 +382,16 @@ pub enum Mutability { Not, } +impl From for hir::Mutability { + fn from(m: Mutability) -> Self { + match m { + Mutability::Mut => hir::MutMutable, + Mutability::Not => hir::MutImmutable, + } + } +} + + #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. @@ -463,6 +473,33 @@ pub enum LocalKind { ReturnPointer, } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct VarBindingForm { + /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? + pub binding_mode: ty::BindingMode, + /// If an explicit type was provided for this variable binding, + /// this holds the source Span of that type. + /// + /// NOTE: If you want to change this to a `HirId`, be wary that + /// doing so breaks incremental compilation (as of this writing), + /// while a `Span` does not cause our tests to fail. + pub opt_ty_info: Option, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub enum BindingForm { + /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. + Var(VarBindingForm), + /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. + ImplicitSelf, +} + +CloneTypeFoldableAndLiftImpls! { BindingForm, } + +impl_stable_hash_for!(struct self::VarBindingForm { binding_mode, opt_ty_info }); + +impl_stable_hash_for!(enum self::BindingForm { Var(binding), ImplicitSelf, }); + /// A MIR local. /// /// This can be a binding declared by the user, a temporary inserted by the compiler, a function @@ -474,8 +511,14 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return place are always mutable. pub mutability: Mutability, - /// True if this corresponds to a user-declared local variable. - pub is_user_variable: bool, + /// Some(binding_mode) if this corresponds to a user-declared local variable. + /// + /// This is solely used for local diagnostics when generating + /// warnings/errors when compiling the current crate, and + /// therefore it need not be visible across crates. pnkfelix + /// currently hypothesized we *need* to wrap this in a + /// `ClearCrossCrate` as long as it carries as `HirId`. + pub is_user_variable: Option>, /// True if this is an internal local /// @@ -605,7 +648,7 @@ impl<'tcx> LocalDecl<'tcx> { }, visibility_scope: OUTERMOST_SOURCE_SCOPE, internal: false, - is_user_variable: false + is_user_variable: None, } } @@ -622,7 +665,7 @@ impl<'tcx> LocalDecl<'tcx> { }, visibility_scope: OUTERMOST_SOURCE_SCOPE, internal: true, - is_user_variable: false + is_user_variable: None, } } @@ -641,7 +684,7 @@ impl<'tcx> LocalDecl<'tcx> { visibility_scope: OUTERMOST_SOURCE_SCOPE, internal: false, name: None, // FIXME maybe we do want some name here? - is_user_variable: false + is_user_variable: None, } } } diff --git a/src/librustc/ty/binding.rs b/src/librustc/ty/binding.rs index 3db61b76cc55..971b3c3d14ae 100644 --- a/src/librustc/ty/binding.rs +++ b/src/librustc/ty/binding.rs @@ -18,6 +18,8 @@ pub enum BindingMode { BindByValue(Mutability), } +CloneTypeFoldableAndLiftImpls! { BindingMode, } + impl BindingMode { pub fn convert(ba: BindingAnnotation) -> BindingMode { match ba { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c43ea0360ee1..a1c773637ec3 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -278,7 +278,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // to the set. let temporary_used_locals: FxHashSet = mbcx.used_mut.iter() - .filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable) + .filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable.is_some()) .cloned() .collect(); diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 7096f91dc1dd..0fd55f752b84 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { + this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| { this.storage_live_binding(block, node, span, OutsideGuard); this.schedule_drop_for_binding(node, span, OutsideGuard); }) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index fbd771fbe500..94b387abe3c1 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -249,7 +249,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { source_info, visibility_scope: source_info.scope, internal: true, - is_user_variable: false + is_user_variable: None, }); let ptr_temp = Place::Local(ptr_temp); let block = unpack!(this.into(&ptr_temp, block, ptr)); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 062a48a8c434..b6af0ed2a4a1 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -307,7 +307,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(!(visibility_scope.is_some() && lint_level.is_explicit()), "can't have both a visibility and a lint scope at the same time"); let mut scope = self.source_scope; - self.visit_bindings(pattern, &mut |this, mutability, name, var, span, ty| { + self.visit_bindings(pattern, &mut |this, mutability, name, mode, var, span, ty| { if visibility_scope.is_none() { visibility_scope = Some(this.new_source_scope(scope_span, LintLevel::Inherited, @@ -325,7 +325,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope, }; let visibility_scope = visibility_scope.unwrap(); - this.declare_binding(source_info, visibility_scope, mutability, name, var, + this.declare_binding(source_info, visibility_scope, mutability, name, mode, var, ty, has_guard); }); visibility_scope @@ -359,11 +359,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, f: &mut F) - where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>) + where F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>) { match *pattern.kind { - PatternKind::Binding { mutability, name, var, ty, ref subpattern, .. } => { - f(self, mutability, name, var, pattern.span, ty); + PatternKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => { + f(self, mutability, name, mode, var, pattern.span, ty); if let Some(subpattern) = subpattern.as_ref() { self.visit_bindings(subpattern, f); } @@ -1118,15 +1118,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scope: SourceScope, mutability: Mutability, name: Name, + mode: BindingMode, var_id: NodeId, var_ty: Ty<'tcx>, has_guard: ArmHasGuard) { - debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, visibility_scope={:?}, \ - source_info={:?})", - var_id, name, var_ty, visibility_scope, source_info); + debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ + visibility_scope={:?}, source_info={:?})", + var_id, name, mode, var_ty, visibility_scope, source_info); let tcx = self.hir.tcx(); + let binding_mode = match mode { + BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()), + BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()), + }; let local = LocalDecl::<'tcx> { mutability, ty: var_ty.clone(), @@ -1134,7 +1139,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { source_info, visibility_scope, internal: false, - is_user_variable: true, + is_user_variable: Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + binding_mode, + // hypothetically, `visit_bindings` could try to unzip + // an outermost hir::Ty as we descend, matching up + // idents in pat; but complex w/ unclear UI payoff. + // Instead, just abandon providing diagnostic info. + opt_ty_info: None, + }))), }; let for_arm_body = self.local_decls.push(local.clone()); let locals = if has_guard.0 && tcx.all_pat_vars_are_implicit_refs_within_guards() { @@ -1145,8 +1157,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { name: Some(name), source_info, visibility_scope, + // FIXME: should these secretly injected ref_for_guard's be marked as `internal`? internal: false, - is_user_variable: true, + is_user_variable: None, }); LocalsForNode::Three { val_for_guard, ref_for_guard, for_arm_body } } else { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index ca7a2daf39d2..35760efbabe6 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -668,7 +668,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scope: source_info.scope, name, internal: false, - is_user_variable: false, + is_user_variable: None, }); } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index f11d80201c28..c703486560dc 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -144,7 +144,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { source_info, visibility_scope: source_info.scope, internal: false, - is_user_variable: false + is_user_variable: None, } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 7ac3b7beb06d..a6017fafcc8d 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -303,7 +303,7 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, source_info, visibility_scope: source_info.scope, internal: false, - is_user_variable: false, + is_user_variable: None, }; let new_ret_local = Local::new(mir.local_decls.len()); mir.local_decls.push(new_ret); @@ -644,7 +644,7 @@ fn create_generator_drop_shim<'a, 'tcx>( source_info, visibility_scope: source_info.scope, internal: false, - is_user_variable: false, + is_user_variable: None, }; make_generator_state_argument_indirect(tcx, def_id, &mut mir); @@ -660,7 +660,7 @@ fn create_generator_drop_shim<'a, 'tcx>( source_info, visibility_scope: source_info.scope, internal: false, - is_user_variable: false, + is_user_variable: None, }; no_landing_pads(tcx, &mut mir);