rustc_mir_transform/
ctfe_limit.rs1use rustc_data_structures::graph::dominators::Dominators;
5use rustc_middle::mir::{
6 BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
7};
8use rustc_middle::ty::TyCtxt;
9use tracing::instrument;
10
11pub(super) struct CtfeLimit;
12
13impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
14 #[instrument(skip(self, _tcx, body))]
15 fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
16 let doms = body.basic_blocks.dominators();
17 let indices: Vec<BasicBlock> = body
18 .basic_blocks
19 .iter_enumerated()
20 .filter_map(|(node, node_data)| {
21 if matches!(node_data.terminator().kind, TerminatorKind::Call { .. } | TerminatorKind::TailCall { .. })
22 || has_back_edge(doms, node, node_data)
24 {
25 Some(node)
26 } else {
27 None
28 }
29 })
30 .collect();
31
32 let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
33 for index in indices {
34 let bbdata = &mut basic_blocks[index];
35 let source_info = bbdata.terminator().source_info;
36 bbdata.statements.push(Statement::new(source_info, StatementKind::ConstEvalCounter));
37 }
38 }
39
40 fn is_required(&self) -> bool {
41 true
42 }
43}
44
45fn has_back_edge(
46 doms: &Dominators<BasicBlock>,
47 node: BasicBlock,
48 node_data: &BasicBlockData<'_>,
49) -> bool {
50 if !doms.is_reachable(node) {
51 return false;
52 }
53 node_data.terminator().successors().any(|succ| doms.dominates(succ, node))
55}