]>
Commit | Line | Data |
---|---|---|
487cf647 FG |
1 | #![deny(rustc::untranslatable_diagnostic)] |
2 | #![deny(rustc::diagnostic_outside_of_impl)] | |
3 | ||
8faf50e0 XL |
4 | use std::collections::VecDeque; |
5 | use std::rc::Rc; | |
6 | ||
c295e0f8 | 7 | use crate::{ |
f9f354fc | 8 | def_use::{self, DefUse}, |
dfeec247 XL |
9 | nll::ToRegionVid, |
10 | region_infer::{Cause, RegionInferenceContext}, | |
11 | }; | |
8faf50e0 | 12 | use rustc_data_structures::fx::FxHashSet; |
ba9703b0 XL |
13 | use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; |
14 | use rustc_middle::mir::{Body, Local, Location}; | |
15 | use rustc_middle::ty::{RegionVid, TyCtxt}; | |
8faf50e0 | 16 | |
923072b8 | 17 | pub(crate) fn find<'tcx>( |
dc9dc135 | 18 | body: &Body<'tcx>, |
8faf50e0 | 19 | regioncx: &Rc<RegionInferenceContext<'tcx>>, |
dc9dc135 | 20 | tcx: TyCtxt<'tcx>, |
8faf50e0 XL |
21 | region_vid: RegionVid, |
22 | start_point: Location, | |
23 | ) -> Option<Cause> { | |
dfeec247 | 24 | let mut uf = UseFinder { body, regioncx, tcx, region_vid, start_point }; |
8faf50e0 XL |
25 | |
26 | uf.find() | |
27 | } | |
28 | ||
dc9dc135 XL |
29 | struct UseFinder<'cx, 'tcx> { |
30 | body: &'cx Body<'tcx>, | |
8faf50e0 | 31 | regioncx: &'cx Rc<RegionInferenceContext<'tcx>>, |
dc9dc135 | 32 | tcx: TyCtxt<'tcx>, |
8faf50e0 XL |
33 | region_vid: RegionVid, |
34 | start_point: Location, | |
8faf50e0 XL |
35 | } |
36 | ||
dc9dc135 | 37 | impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { |
8faf50e0 XL |
38 | fn find(&mut self) -> Option<Cause> { |
39 | let mut queue = VecDeque::new(); | |
0bf4aa26 | 40 | let mut visited = FxHashSet::default(); |
8faf50e0 XL |
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 | ||
dc9dc135 | 52 | let block_data = &self.body[p.block]; |
8faf50e0 XL |
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() { | |
9fa01778 | 67 | queue.push_back(p.successor_within_block()); |
8faf50e0 XL |
68 | } else { |
69 | queue.extend( | |
70 | block_data | |
71 | .terminator() | |
72 | .successors() | |
923072b8 FG |
73 | .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind()) |
74 | .map(|bb| Location { statement_index: 0, block: bb }), | |
8faf50e0 XL |
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 { | |
dc9dc135 | 86 | body: self.body, |
8faf50e0 XL |
87 | tcx: self.tcx, |
88 | region_vid: self.region_vid, | |
8faf50e0 XL |
89 | def_use_result: None, |
90 | }; | |
91 | ||
92 | thing.apply(location, &mut visitor); | |
93 | ||
94 | visitor.def_use_result | |
95 | } | |
96 | } | |
97 | ||
dc9dc135 XL |
98 | struct DefUseVisitor<'cx, 'tcx> { |
99 | body: &'cx Body<'tcx>, | |
100 | tcx: TyCtxt<'tcx>, | |
8faf50e0 | 101 | region_vid: RegionVid, |
8faf50e0 XL |
102 | def_use_result: Option<DefUseResult>, |
103 | } | |
104 | ||
105 | enum DefUseResult { | |
106 | Def, | |
8faf50e0 | 107 | UseLive { local: Local }, |
8faf50e0 XL |
108 | UseDrop { local: Local }, |
109 | } | |
110 | ||
dc9dc135 | 111 | impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { |
064997fb | 112 | fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { |
dc9dc135 | 113 | let local_ty = self.body.local_decls[local].ty; |
8faf50e0 XL |
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 { | |
f9f354fc | 123 | self.def_use_result = match def_use::categorize(context) { |
b7449926 XL |
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 | }; | |
8faf50e0 XL |
129 | } |
130 | } | |
131 | } |