Skip to content

Commit

Permalink
Allow MIR borrowck to catch unused mutable locals
Browse files Browse the repository at this point in the history
  • Loading branch information
KiChjang committed Apr 28, 2018
1 parent 1eb0cef commit 2338adf
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 7 deletions.
14 changes: 14 additions & 0 deletions src/librustc/mir/mod.rs
Expand Up @@ -247,6 +247,20 @@ impl<'tcx> Mir<'tcx> {
})
}

/// Returns an iterator over all user-declared mutable locals.
#[inline]
pub fn mut_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);
let decl = &self.local_decls[local];
if decl.is_user_variable && decl.mutability == Mutability::Mut {
Some(local)
} else {
None
}
})
}

/// Returns an iterator over all function arguments.
#[inline]
pub fn args_iter(&self) -> impl Iterator<Item=Local> {
Expand Down
37 changes: 30 additions & 7 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -17,10 +17,11 @@ use rustc::hir::map::definitions::DefPathData;
use rustc::infer::InferCtxt;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place};
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
use rustc::mir::{ClosureRegionRequirements, Local};
use rustc::lint::builtin::UNUSED_MUT;
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, ClearCrossCrate, Local};
use rustc::mir::{Location, Place, Mir, Mutability, Operand, Projection, ProjectionElem};
use rustc::mir::{Rvalue, Field, Statement, StatementKind, Terminator, TerminatorKind};
use rustc::mir::ClosureRegionRequirements;

use rustc_data_structures::control_flow_graph::dominators::Dominators;
use rustc_data_structures::fx::FxHashSet;
Expand Down Expand Up @@ -236,7 +237,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
moved_error_reported: FxHashSet(),
nonlexical_regioncx: regioncx,
nonlexical_regioncx: opt_regioncx,
used_mut: FxHashSet(),
nonlexical_cause_info: None,
borrow_set,
dominators,
Expand Down Expand Up @@ -287,6 +289,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
/// This field keeps track of errors reported in the checking of moved variables,
/// so that we don't report report seemingly duplicate errors.
moved_error_reported: FxHashSet<Place<'tcx>>,
/// This field keeps track of all the local variables that are declared mut and are mutated.
/// Used for the warning issued by an unused mutable local variable.
used_mut: FxHashSet<Local>,
/// Non-lexical region inference context, if NLL is enabled. This
/// contains the results from region inference and lets us e.g.
/// find out which CFG points are contained in each borrow region.
Expand Down Expand Up @@ -434,6 +439,22 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx

self.check_activations(location, span, flow_state);

for local in self.mir.mut_vars_iter().filter(|local| !self.used_mut.contains(local)) {
if let ClearCrossCrate::Set(ref vsi) = self.mir.visibility_scope_info {
let source_info = self.mir.local_decls[local].source_info;
let mut_span = self.tcx.sess.codemap().span_until_non_whitespace(source_info.span);

self.tcx.struct_span_lint_node(
UNUSED_MUT,
vsi[source_info.scope].lint_root,
source_info.span,
"variable does not need to be mutable"
)
.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
.emit();
}
}

match term.kind {
TerminatorKind::SwitchInt {
ref discr,
Expand Down Expand Up @@ -1594,7 +1615,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
///
/// Returns true if an error is reported, false otherwise.
fn check_access_permissions(
&self,
&mut self,
(place, span): (&Place<'tcx>, Span),
kind: ReadOrWrite,
is_local_mutation_allowed: LocalMutationIsAllowed,
Expand Down Expand Up @@ -1631,7 +1652,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
err.emit();
},
Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {

if let Place::Local(local) = *place {
self.used_mut.insert(local);
}
if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) {
error_reported = true;
let mut err_info = None;
Expand Down

0 comments on commit 2338adf

Please sign in to comment.