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