Skip to content

Instantly share code, notes, and snippets.

@lqd

lqd/mod.rs Secret

Last active June 15, 2018 14:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lqd/7e178cb9ac8302e24272965048627f21 to your computer and use it in GitHub Desktop.
Save lqd/7e178cb9ac8302e24272965048627f21 to your computer and use it in GitHub Desktop.
librustc_mir/borrow_check/mod.rs with stats about MirVisitors' `super_mir` calls in different "regions" of `do_mir_borrowck`
fn mir_borrowck<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> BorrowCheckResult<'tcx> {
// called 1883 times in clap, indirectly recursive (w/ depth of 4)
// generating 11777 "super_mir" calls out of 31005 total
let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() {
return BorrowCheckResult {
closure_requirements: None,
used_mut_upvars: SmallVec::new(),
};
}
let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
let input_mir: &Mir = &input_mir.borrow();
do_mir_borrowck(&infcx, input_mir, def_id)
});
debug!("mir_borrowck done");
opt_closure_req
}
fn do_mir_borrowck<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
input_mir: &Mir<'gcx>,
def_id: DefId,
) -> BorrowCheckResult<'gcx> {
let tcx = infcx.tcx;
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id);
let id = tcx.hir
.as_local_node_id(def_id)
.expect("do_mir_borrowck: non-local DefId");
// region 1 start
// Replace all regions with fresh inference variables. This
// requires first making our own copy of the MIR. This copy will
// be modified (in place) to contain non-lexical lifetimes. It
// will have a lifetime tied to the inference context.
let mut mir: Mir<'tcx> = input_mir.clone();
let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir);
let mir = &mir; // no further changes
let location_table = &LocationTable::new(mir);
// region 1 end - generating 1883 "super_mir" calls out of 11777 (per depth 0 to 4: 1580/266/22/14/1)
// region 2 start
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
Ok(move_data) => move_data,
Err((move_data, move_errors)) => {
for move_error in move_errors {
let (span, kind): (Span, IllegalMoveOriginKind) = match move_error {
MoveError::UnionMove { .. } => {
unimplemented!("don't know how to report union move errors yet.")
}
MoveError::IllegalMove {
cannot_move_out_of: o,
} => (o.span, o.kind),
};
let origin = Origin::Mir;
let mut err = match kind {
IllegalMoveOriginKind::Static => {
tcx.cannot_move_out_of(span, "static item", origin)
}
IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => {
// Inspect the type of the content behind the
// borrow to provide feedback about why this
// was a move rather than a copy.
match ty.sty {
ty::TyArray(..) | ty::TySlice(..) =>
tcx.cannot_move_out_of_interior_noncopy(span, ty, None, origin),
_ => tcx.cannot_move_out_of(span, "borrowed content", origin)
}
}
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
tcx.cannot_move_out_of_interior_of_drop(span, ty, origin)
}
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
tcx.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index), origin)
}
};
err.emit();
}
move_data
}
};
// region 2 end - generating 0 "super_mir" calls out of 11777
// region 3 start
let mdpe = MoveDataParamEnv {
move_data: move_data,
param_env: param_env,
};
let body_id = match tcx.def_key(def_id).disambiguated_data.data {
DefPathData::StructCtor | DefPathData::EnumVariant(_) => None,
_ => Some(tcx.hir.body_owned_by(id)),
};
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let mut flow_inits = FlowAtLocation::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
let flow_uninits = FlowAtLocation::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
let flow_move_outs = FlowAtLocation::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MovingOutStatements::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().moves[i]),
));
let flow_ever_inits = FlowAtLocation::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
EverInitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
));
// region 3 end - generating 0 "super_mir" calls out of 11777
// region 4 start
let borrow_set = Rc::new(BorrowSet::build(tcx, mir));
// If we are in non-lexical mode, compute the non-lexical lifetimes.
let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
infcx,
def_id,
free_regions,
mir,
location_table,
param_env,
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
);
let regioncx = Rc::new(regioncx);
let flow_inits = flow_inits; // remove mut
// region 4 end - generating 1883 "super_mir" calls out of 11777 (per depth 0 to 4: 1580/266/22/14/1)
// region 5 start
let flow_borrows = FlowAtLocation::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, regioncx.clone(), def_id, body_id, &borrow_set),
|rs, i| DebugFormatted::new(&rs.location(i)),
));
let movable_generator = match tcx.hir.get(id) {
hir::map::Node::NodeExpr(&hir::Expr {
node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)),
..
}) => false,
_ => true,
};
// region 5 end - generating 0 "super_mir" calls out of 11777
// region 6 start
let dominators = mir.dominators();
// region 6 end - generating 0 "super_mir" calls out of 11777
// region 7 start
let mut mbcx = MirBorrowckCtxt {
tcx: tcx,
mir: mir,
mir_def_id: def_id,
move_data: &mdpe.move_data,
param_env: param_env,
movable_generator,
locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
hir::BodyOwnerKind::Fn => true,
},
access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
moved_error_reported: FxHashSet(),
nonlexical_regioncx: regioncx,
used_mut: FxHashSet(),
used_mut_upvars: SmallVec::new(),
borrow_set,
dominators,
};
let mut state = Flows::new(
flow_borrows,
flow_inits,
flow_uninits,
flow_move_outs,
flow_ever_inits,
polonius_output,
);
// region 7 end - generating 0 "super_mir" calls out of 11777
// region 8 start
mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
// For each non-user used mutable variable, check if it's been assigned from
// a user-declared local. If so, then put that local into the used_mut set.
// Note that this set is expected to be small - only upvars from closures
// would have a chance of erroneously adding non-user-defined mutable vars
// to the set.
let temporary_used_locals: FxHashSet<Local> =
mbcx.used_mut.iter()
.filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable)
.cloned()
.collect();
// region 8 end - generating 0 "super_mir" calls out of 11777
// region 9 start
for local in temporary_used_locals {
let assignments = mbcx.mir.find_assignments(local);
for location in assignments {
for moi in &mbcx.move_data.loc_map[location] {
let mpi = &mbcx.move_data.moves[*moi].path;
let path = &mbcx.move_data.move_paths[*mpi];
debug!("assignment of {:?} to {:?}, adding {:?} to used mutable set",
path.place, local, path.place);
if let Place::Local(user_local) = path.place {
mbcx.used_mut.insert(user_local);
}
}
}
}
// region 9 end - generating 8011 "super_mir" calls out of 11777 (per depth 0 to 4: 7966/31/13/0/0)
// region 10 start
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !mbcx.used_mut.contains(local)) {
if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
let local_decl = &mbcx.mir.local_decls[local];
// Skip implicit `self` argument for closures
if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) {
continue;
}
// Skip over locals that begin with an underscore or have no name
match local_decl.name {
Some(name) => if name.as_str().starts_with("_") { continue; },
None => continue,
}
let span = local_decl.source_info.span;
let mut_span = tcx.sess.codemap().span_until_non_whitespace(span);
tcx.struct_span_lint_node(
UNUSED_MUT,
vsi[local_decl.source_info.scope].lint_root,
span,
"variable does not need to be mutable"
)
.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
.emit();
}
}
// region 10 end - generating 0 "super_mir" calls out of 11777
BorrowCheckResult {
closure_requirements: opt_closure_req,
used_mut_upvars: mbcx.used_mut_upvars,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment