1
Fork 0

Thread info about form of variable bindings, including spans of arg types, 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.)
This commit is contained in:
Felix S. Klock II 2018-06-07 15:25:08 +02:00
parent 6ec1b626ba
commit cac61267a7
9 changed files with 85 additions and 27 deletions

View file

@ -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)
@ -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
@ -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<BasicBlock> for Mir<'tcx> {
}
}
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum ClearCrossCrate<T> {
Clear,
Set(T)
@ -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.
@ -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
@ -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
///
@ -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,
}
}
}

View file

@ -18,6 +18,8 @@ pub enum BindingMode {
BindByValue(Mutability),
}
CloneTypeFoldableAndLiftImpls! { BindingMode, }
impl BindingMode {
pub fn convert(ba: BindingAnnotation) -> BindingMode {
match ba {

View file

@ -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();

View file

@ -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);
})

View file

@ -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));

View file

@ -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<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);
}
@ -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 {

View file

@ -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,
});
}

View file

@ -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,
}
}

View file

@ -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);