rustc_utils/mir/
borrowck_facts.rs1use std::sync::atomic::{AtomicBool, Ordering};
4
5use rustc_borrowck::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
6use rustc_data_structures::fx::FxHashSet as HashSet;
7use rustc_hir::def_id::LocalDefId;
8use rustc_middle::{
9 mir::{Body, StatementKind, TerminatorKind},
10 ty::TyCtxt,
11 util::Providers,
12};
13
14use crate::{BodyExt, block_timer, cache::Cache};
15
16pub fn simplify_mir(body: &mut Body<'_>) {
21 let return_blocks = body
22 .all_returns()
23 .filter_map(|loc| {
24 let bb = &body.basic_blocks[loc.block];
25 (bb.statements.len() == 0).then_some(loc.block)
26 })
27 .collect::<HashSet<_>>();
28
29 for block in body.basic_blocks_mut() {
30 block.statements.retain(|stmt| {
31 !matches!(
32 stmt.kind,
33 StatementKind::StorageLive(..) | StatementKind::StorageDead(..)
34 )
35 });
36
37 let terminator = block.terminator_mut();
38 terminator.kind = match terminator.kind {
39 TerminatorKind::FalseEdge { real_target, .. } => TerminatorKind::Goto {
40 target: real_target,
41 },
42 TerminatorKind::Goto { target } if return_blocks.contains(&target) => {
45 TerminatorKind::Return
46 }
47 _ => continue,
48 }
49 }
50}
51
52static SIMPLIFY_MIR: AtomicBool = AtomicBool::new(false);
53
54pub fn enable_mir_simplification() {
55 SIMPLIFY_MIR.store(true, Ordering::SeqCst);
56}
57
58pub fn override_queries(_session: &rustc_session::Session, local: &mut Providers) {
63 local.queries.mir_borrowck = mir_borrowck;
64}
65
66thread_local! {
67 static MIR_BODIES: Cache<LocalDefId, BodyWithBorrowckFacts<'static>> = Cache::default();
68}
69
70fn mir_borrowck(
71 tcx: TyCtxt<'_>,
72 def_id: LocalDefId,
73) -> rustc_middle::queries::mir_borrowck::ProvidedValue<'_> {
74 block_timer!(&format!(
75 "get_bodies_with_borrowck_facts for {}",
76 tcx.def_path_debug_str(def_id.to_def_id())
77 ));
78
79 let mut bodies_with_facts = rustc_borrowck::consumers::get_bodies_with_borrowck_facts(
80 tcx,
81 def_id,
82 ConsumerOptions::PoloniusInputFacts,
83 );
84
85 for (def_id, mut body_with_facts) in bodies_with_facts.drain() {
86 if SIMPLIFY_MIR.load(Ordering::SeqCst) {
87 simplify_mir(&mut body_with_facts.body);
88 }
89
90 let body_with_facts: BodyWithBorrowckFacts<'static> =
92 unsafe { std::mem::transmute(body_with_facts) };
93 MIR_BODIES.with(|cache| {
94 cache.get(&def_id, |_| body_with_facts);
95 });
96 }
97
98 let mut providers = Providers::default();
99 rustc_borrowck::provide(&mut providers.queries);
100 let original_mir_borrowck = providers.queries.mir_borrowck;
101 original_mir_borrowck(tcx, def_id)
102}
103
104pub fn get_body_with_borrowck_facts<'tcx>(
116 tcx: TyCtxt<'tcx>,
117 def_id: LocalDefId,
118) -> &'tcx BodyWithBorrowckFacts<'tcx> {
119 MIR_BODIES.with(|cache| {
120 if !cache.contains_key(&def_id) {
124 let checkable_def_id = if tcx.is_typeck_child(def_id.to_def_id()) { tcx.local_parent(def_id) } else { def_id };
127 let _ = tcx.mir_borrowck(checkable_def_id);
128 }
129
130 let body = cache.get(&def_id, |_| panic!("mir_borrowck override should have stored body for item: {def_id:?}. Are you sure you registered borrowck_facts::override_queries?"));
131 unsafe {
132 std::mem::transmute::<
133 &'_ BodyWithBorrowckFacts<'static>,
134 &'tcx BodyWithBorrowckFacts<'tcx>,
135 >(body)
136 }
137 })
138}