rustc_borrowck/polonius/legacy/
accesses.rs

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location, Place};
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
use tracing::debug;

use crate::def_use::{self, DefUse};
use crate::facts::AllFacts;
use crate::location::{LocationIndex, LocationTable};
use crate::universal_regions::UniversalRegions;

/// Emit polonius facts for variable defs, uses, drops, and path accesses.
pub(crate) fn emit_access_facts<'tcx>(
    tcx: TyCtxt<'tcx>,
    facts: &mut AllFacts,
    body: &Body<'tcx>,
    location_table: &LocationTable,
    move_data: &MoveData<'tcx>,
    universal_regions: &UniversalRegions<'tcx>,
) {
    let mut extractor = AccessFactsExtractor { facts, move_data, location_table };
    extractor.visit_body(body);

    for (local, local_decl) in body.local_decls.iter_enumerated() {
        debug!("add use_of_var_derefs_origin facts - local={:?}, type={:?}", local, local_decl.ty);
        tcx.for_each_free_region(&local_decl.ty, |region| {
            let region_vid = universal_regions.to_region_vid(region);
            facts.use_of_var_derefs_origin.push((local, region_vid.into()));
        });
    }
}

/// MIR visitor extracting point-wise facts about accesses.
struct AccessFactsExtractor<'a, 'tcx> {
    facts: &'a mut AllFacts,
    move_data: &'a MoveData<'tcx>,
    location_table: &'a LocationTable,
}

impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
    fn location_to_index(&self, location: Location) -> LocationIndex {
        self.location_table.mid_index(location)
    }
}

impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
        match def_use::categorize(context) {
            Some(DefUse::Def) => {
                debug!("AccessFactsExtractor - emit def");
                self.facts.var_defined_at.push((local, self.location_to_index(location)));
            }
            Some(DefUse::Use) => {
                debug!("AccessFactsExtractor - emit use");
                self.facts.var_used_at.push((local, self.location_to_index(location)));
            }
            Some(DefUse::Drop) => {
                debug!("AccessFactsExtractor - emit drop");
                self.facts.var_dropped_at.push((local, self.location_to_index(location)));
            }
            _ => (),
        }
    }

    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
        self.super_place(place, context, location);

        match context {
            PlaceContext::NonMutatingUse(_)
            | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
                let path = match self.move_data.rev_lookup.find(place.as_ref()) {
                    LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path,
                    _ => {
                        // There's no path access to emit.
                        return;
                    }
                };
                debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})");
                self.facts.path_accessed_at_base.push((path, self.location_to_index(location)));
            }

            _ => {}
        }
    }
}