]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/diagnostics/find_use.rs
Auto merge of #101784 - reitermarkus:const-memchr, r=thomcc
[rust.git] / compiler / rustc_borrowck / src / diagnostics / find_use.rs
1 use std::collections::VecDeque;
2 use std::rc::Rc;
3
4 use crate::{
5     def_use::{self, DefUse},
6     nll::ToRegionVid,
7     region_infer::{Cause, RegionInferenceContext},
8 };
9 use rustc_data_structures::fx::FxHashSet;
10 use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
11 use rustc_middle::mir::{Body, Local, Location};
12 use rustc_middle::ty::{RegionVid, TyCtxt};
13
14 pub(crate) fn find<'tcx>(
15     body: &Body<'tcx>,
16     regioncx: &Rc<RegionInferenceContext<'tcx>>,
17     tcx: TyCtxt<'tcx>,
18     region_vid: RegionVid,
19     start_point: Location,
20 ) -> Option<Cause> {
21     let mut uf = UseFinder { body, regioncx, tcx, region_vid, start_point };
22
23     uf.find()
24 }
25
26 struct UseFinder<'cx, 'tcx> {
27     body: &'cx Body<'tcx>,
28     regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
29     tcx: TyCtxt<'tcx>,
30     region_vid: RegionVid,
31     start_point: Location,
32 }
33
34 impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
35     fn find(&mut self) -> Option<Cause> {
36         let mut queue = VecDeque::new();
37         let mut visited = FxHashSet::default();
38
39         queue.push_back(self.start_point);
40         while let Some(p) = queue.pop_front() {
41             if !self.regioncx.region_contains(self.region_vid, p) {
42                 continue;
43             }
44
45             if !visited.insert(p) {
46                 continue;
47             }
48
49             let block_data = &self.body[p.block];
50
51             match self.def_use(p, block_data.visitable(p.statement_index)) {
52                 Some(DefUseResult::Def) => {}
53
54                 Some(DefUseResult::UseLive { local }) => {
55                     return Some(Cause::LiveVar(local, p));
56                 }
57
58                 Some(DefUseResult::UseDrop { local }) => {
59                     return Some(Cause::DropVar(local, p));
60                 }
61
62                 None => {
63                     if p.statement_index < block_data.statements.len() {
64                         queue.push_back(p.successor_within_block());
65                     } else {
66                         queue.extend(
67                             block_data
68                                 .terminator()
69                                 .successors()
70                                 .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind())
71                                 .map(|bb| Location { statement_index: 0, block: bb }),
72                         );
73                     }
74                 }
75             }
76         }
77
78         None
79     }
80
81     fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> {
82         let mut visitor = DefUseVisitor {
83             body: self.body,
84             tcx: self.tcx,
85             region_vid: self.region_vid,
86             def_use_result: None,
87         };
88
89         thing.apply(location, &mut visitor);
90
91         visitor.def_use_result
92     }
93 }
94
95 struct DefUseVisitor<'cx, 'tcx> {
96     body: &'cx Body<'tcx>,
97     tcx: TyCtxt<'tcx>,
98     region_vid: RegionVid,
99     def_use_result: Option<DefUseResult>,
100 }
101
102 enum DefUseResult {
103     Def,
104     UseLive { local: Local },
105     UseDrop { local: Local },
106 }
107
108 impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
109     fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
110         let local_ty = self.body.local_decls[local].ty;
111
112         let mut found_it = false;
113         self.tcx.for_each_free_region(&local_ty, |r| {
114             if r.to_region_vid() == self.region_vid {
115                 found_it = true;
116             }
117         });
118
119         if found_it {
120             self.def_use_result = match def_use::categorize(context) {
121                 Some(DefUse::Def) => Some(DefUseResult::Def),
122                 Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
123                 Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
124                 None => None,
125             };
126         }
127     }
128 }