1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::{Local, Location, Place};

use rustc_data_structures::fx::FxHashSet;

use borrow_check::MirBorrowckCtxt;
use util::collect_writes::is_place_assignment;

impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
    /// Walks the MIR looking for assignments to a set of locals, as part of the unused mutable
    /// local variables lint, to update the context's `used_mut` in a single walk.
    crate fn gather_used_muts(&mut self, locals: FxHashSet<Local>) {
        let mut visitor = GatherUsedMutsVisitor {
            needles: locals,
            mbcx: self,
        };
        visitor.visit_mir(visitor.mbcx.mir);
    }
}

/// MIR visitor gathering the assignments to a set of locals, in a single walk.
/// 'visit = the duration of the MIR walk
struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> {
    needles: FxHashSet<Local>,
    mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
}

impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> {
    fn visit_local(
        &mut self,
        local: &Local,
        place_context: PlaceContext<'tcx>,
        location: Location,
    ) {
        if !self.needles.contains(local) {
            return;
        }

        if is_place_assignment(&place_context) {
            // Propagate the Local assigned at this Location as a used mutable local variable
            for moi in &self.mbcx.move_data.loc_map[location] {
                let mpi = &self.mbcx.move_data.moves[*moi].path;
                let path = &self.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 {
                    self.mbcx.used_mut.insert(user_local);
                }
            }
        }
    }
}