Skip to content

Commit

Permalink
Thread info about form of variable bindings, including spans of arg t…
Browse files Browse the repository at this point in the history
…ypes, down into `mir::LocalDecls`.

As a drive-by: the ref_for_guards created by `fn declare_binding`
should not have been tagged as user_variables in the first
place. These secret internal locals are *pointers* to user variables,
but themselves are not such (IMO. For now at least.)
  • Loading branch information
pnkfelix committed Jun 19, 2018
1 parent 6ec1b62 commit cac6126
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 27 deletions.
61 changes: 52 additions & 9 deletions src/librustc/mir/mod.rs
Expand Up @@ -228,7 +228,7 @@ impl<'tcx> Mir<'tcx> {
pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + '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)
Expand All @@ -241,7 +241,7 @@ impl<'tcx> Mir<'tcx> {
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + '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
Expand All @@ -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)
Expand Down Expand Up @@ -351,7 +351,7 @@ impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> {
}
}

#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum ClearCrossCrate<T> {
Clear,
Set(T)
Expand Down Expand Up @@ -382,6 +382,16 @@ pub enum Mutability {
Not,
}

impl From<Mutability> 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.
Expand Down Expand Up @@ -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<Span>,
}

#[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
Expand All @@ -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<ClearCrossCrate<BindingForm>>,

/// True if this is an internal local
///
Expand Down Expand Up @@ -605,7 +648,7 @@ impl<'tcx> LocalDecl<'tcx> {
},
visibility_scope: OUTERMOST_SOURCE_SCOPE,
internal: false,
is_user_variable: false
is_user_variable: None,
}
}

Expand All @@ -622,7 +665,7 @@ impl<'tcx> LocalDecl<'tcx> {
},
visibility_scope: OUTERMOST_SOURCE_SCOPE,
internal: true,
is_user_variable: false
is_user_variable: None,
}
}

Expand All @@ -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,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ty/binding.rs
Expand Up @@ -18,6 +18,8 @@ pub enum BindingMode {
BindByValue(Mutability),
}

CloneTypeFoldableAndLiftImpls! { BindingMode, }

impl BindingMode {
pub fn convert(ba: BindingAnnotation) -> BindingMode {
match ba {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -278,7 +278,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
// to the set.
let temporary_used_locals: FxHashSet<Local> =
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();

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/block.rs
Expand Up @@ -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);
})
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/expr/into.rs
Expand Up @@ -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));
Expand Down
33 changes: 23 additions & 10 deletions src/librustc_mir/build/matches/mod.rs
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -359,11 +359,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}

pub fn visit_bindings<F>(&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);
}
Expand Down Expand Up @@ -1118,23 +1118,35 @@ 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(),
name: Some(name),
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() {
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/mod.rs
Expand Up @@ -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,
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/shim.rs
Expand Up @@ -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,
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/librustc_mir/transform/generator.rs
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit cac6126

Please sign in to comment.