use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, Place}; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData}; use tracing::debug; use super::{LocationIndex, PoloniusFacts, PoloniusLocationTable}; use crate::def_use::{self, DefUse}; use crate::universal_regions::UniversalRegions; /// Emit polonius facts for variable defs, uses, drops, and path accesses. pub(crate) fn emit_access_facts<'tcx>( tcx: TyCtxt<'tcx>, facts: &mut PoloniusFacts, body: &Body<'tcx>, location_table: &PoloniusLocationTable, move_data: &MoveData<'tcx>, universal_regions: &UniversalRegions<'tcx>, ) { let mut extractor = AccessFactsExtractor { facts, move_data, location_table }; extractor.visit_body(body); for (local, local_decl) in body.local_decls.iter_enumerated() { debug!("add use_of_var_derefs_origin facts - local={:?}, type={:?}", local, local_decl.ty); tcx.for_each_free_region(&local_decl.ty, |region| { let region_vid = universal_regions.to_region_vid(region); facts.use_of_var_derefs_origin.push((local, region_vid.into())); }); } } /// MIR visitor extracting point-wise facts about accesses. struct AccessFactsExtractor<'a, 'tcx> { facts: &'a mut PoloniusFacts, move_data: &'a MoveData<'tcx>, location_table: &'a PoloniusLocationTable, } impl<'tcx> AccessFactsExtractor<'_, 'tcx> { fn location_to_index(&self, location: Location) -> LocationIndex { self.location_table.mid_index(location) } } impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { match def_use::categorize(context) { Some(DefUse::Def) => { debug!("AccessFactsExtractor - emit def"); self.facts.var_defined_at.push((local, self.location_to_index(location))); } Some(DefUse::Use) => { debug!("AccessFactsExtractor - emit use"); self.facts.var_used_at.push((local, self.location_to_index(location))); } Some(DefUse::Drop) => { debug!("AccessFactsExtractor - emit drop"); self.facts.var_dropped_at.push((local, self.location_to_index(location))); } _ => (), } } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { self.super_place(place, context, location); match context { PlaceContext::NonMutatingUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { let path = match self.move_data.rev_lookup.find(place.as_ref()) { LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path, _ => { // There's no path access to emit. return; } }; debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})"); self.facts.path_accessed_at_base.push((path, self.location_to_index(location))); } _ => {} } } }