]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
Rollup merge of #69645 - DutchGhost:const-forget-tests, r=Dylan-DPC
[rust.git] / src / librustc_mir / borrow_check / type_check / liveness / polonius.rs
1 use crate::borrow_check::location::{LocationIndex, LocationTable};
2 use crate::dataflow::indexes::MovePathIndex;
3 use crate::dataflow::move_paths::{LookupResult, MoveData};
4 use crate::util::liveness::{categorize, DefUse};
5 use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
6 use rustc::mir::{Local, Location, Place, ReadOnlyBodyAndCache};
7 use rustc::ty::subst::GenericArg;
8
9 use super::TypeChecker;
10
11 type VarPointRelation = Vec<(Local, LocationIndex)>;
12 type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
13
14 struct UseFactsExtractor<'me> {
15     var_defined_at: &'me mut VarPointRelation,
16     var_used_at: &'me mut VarPointRelation,
17     location_table: &'me LocationTable,
18     var_dropped_at: &'me mut VarPointRelation,
19     move_data: &'me MoveData<'me>,
20     path_accessed_at_base: &'me mut PathPointRelation,
21 }
22
23 // A Visitor to walk through the MIR and extract point-wise facts
24 impl UseFactsExtractor<'_> {
25     fn location_to_index(&self, location: Location) -> LocationIndex {
26         self.location_table.mid_index(location)
27     }
28
29     fn insert_def(&mut self, local: Local, location: Location) {
30         debug!("UseFactsExtractor::insert_def()");
31         self.var_defined_at.push((local, self.location_to_index(location)));
32     }
33
34     fn insert_use(&mut self, local: Local, location: Location) {
35         debug!("UseFactsExtractor::insert_use()");
36         self.var_used_at.push((local, self.location_to_index(location)));
37     }
38
39     fn insert_drop_use(&mut self, local: Local, location: Location) {
40         debug!("UseFactsExtractor::insert_drop_use()");
41         self.var_dropped_at.push((local, self.location_to_index(location)));
42     }
43
44     fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
45         debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location);
46         self.path_accessed_at_base.push((path, self.location_table.start_index(location)));
47     }
48
49     fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
50         match self.move_data.rev_lookup.find(place.as_ref()) {
51             LookupResult::Exact(mpi) => Some(mpi),
52             LookupResult::Parent(mmpi) => mmpi,
53         }
54     }
55 }
56
57 impl Visitor<'tcx> for UseFactsExtractor<'_> {
58     fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
59         match categorize(context) {
60             Some(DefUse::Def) => self.insert_def(local, location),
61             Some(DefUse::Use) => self.insert_use(local, location),
62             Some(DefUse::Drop) => self.insert_drop_use(local, location),
63             _ => (),
64         }
65     }
66
67     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
68         self.super_place(place, context, location);
69         match context {
70             PlaceContext::NonMutatingUse(_) => {
71                 if let Some(mpi) = self.place_to_mpi(place) {
72                     self.insert_path_access(mpi, location);
73                 }
74             }
75
76             PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
77                 if let Some(mpi) = self.place_to_mpi(place) {
78                     self.insert_path_access(mpi, location);
79                 }
80             }
81             _ => (),
82         }
83     }
84 }
85
86 pub(super) fn populate_access_facts(
87     typeck: &mut TypeChecker<'_, 'tcx>,
88     body: ReadOnlyBodyAndCache<'_, 'tcx>,
89     location_table: &LocationTable,
90     move_data: &MoveData<'_>,
91     dropped_at: &mut Vec<(Local, Location)>,
92 ) {
93     debug!("populate_access_facts()");
94
95     if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
96         let mut extractor = UseFactsExtractor {
97             var_defined_at: &mut facts.var_defined_at,
98             var_used_at: &mut facts.var_used_at,
99             var_dropped_at: &mut facts.var_dropped_at,
100             path_accessed_at_base: &mut facts.path_accessed_at_base,
101             location_table,
102             move_data,
103         };
104         extractor.visit_body(body);
105
106         facts.var_dropped_at.extend(
107             dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))),
108         );
109
110         for (local, local_decl) in body.local_decls.iter_enumerated() {
111             debug!(
112                 "add use_of_var_derefs_origin facts - local={:?}, type={:?}",
113                 local, local_decl.ty
114             );
115             let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
116             let universal_regions = &typeck.borrowck_context.universal_regions;
117             typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
118                 let region_vid = universal_regions.to_region_vid(region);
119                 facts.use_of_var_derefs_origin.push((local, region_vid));
120             });
121         }
122     }
123 }
124
125 // For every potentially drop()-touched region `region` in `local`'s type
126 // (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
127 pub(super) fn add_drop_of_var_derefs_origin(
128     typeck: &mut TypeChecker<'_, 'tcx>,
129     local: Local,
130     kind: &GenericArg<'tcx>,
131 ) {
132     debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind);
133     if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
134         let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
135         let universal_regions = &typeck.borrowck_context.universal_regions;
136         typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
137             let region_vid = universal_regions.to_region_vid(drop_live_region);
138             facts.drop_of_var_derefs_origin.push((local, region_vid));
139         });
140     }
141 }