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:
parent
6ec1b626ba
commit
cac61267a7
9 changed files with 85 additions and 27 deletions
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ pub enum BindingMode {
|
|||
BindByValue(Mutability),
|
||||
}
|
||||
|
||||
CloneTypeFoldableAndLiftImpls! { BindingMode, }
|
||||
|
||||
impl BindingMode {
|
||||
pub fn convert(ba: BindingAnnotation) -> BindingMode {
|
||||
match ba {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue