1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
4 use std::collections::VecDeque;
8 def_use::{self, DefUse},
10 region_infer::{Cause, RegionInferenceContext},
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};
17 pub(crate) fn find<'tcx>(
19 regioncx: &Rc<RegionInferenceContext<'tcx>>,
21 region_vid: RegionVid,
22 start_point: Location,
24 let mut uf = UseFinder { body, regioncx, tcx, region_vid, start_point };
29 struct UseFinder<'cx, 'tcx> {
30 body: &'cx Body<'tcx>,
31 regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
33 region_vid: RegionVid,
34 start_point: Location,
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();
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) {
48 if !visited.insert(p) {
52 let block_data = &self.body[p.block];
54 match self.def_use(p, block_data.visitable(p.statement_index)) {
55 Some(DefUseResult::Def) => {}
57 Some(DefUseResult::UseLive { local }) => {
58 return Some(Cause::LiveVar(local, p));
61 Some(DefUseResult::UseDrop { local }) => {
62 return Some(Cause::DropVar(local, p));
66 if p.statement_index < block_data.statements.len() {
67 queue.push_back(p.successor_within_block());
73 .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind())
74 .map(|bb| Location { statement_index: 0, block: bb }),
84 fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> {
85 let mut visitor = DefUseVisitor {
88 region_vid: self.region_vid,
92 thing.apply(location, &mut visitor);
94 visitor.def_use_result
98 struct DefUseVisitor<'cx, 'tcx> {
99 body: &'cx Body<'tcx>,
101 region_vid: RegionVid,
102 def_use_result: Option<DefUseResult>,
107 UseLive { local: Local },
108 UseDrop { local: Local },
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;
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 {
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 }),