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