rustc_mir_transform/strip_debuginfo.rs
1use rustc_middle::mir::*;
2use rustc_middle::ty::TyCtxt;
3use rustc_mir_dataflow::debuginfo::debuginfo_locals;
4use rustc_session::config::MirStripDebugInfo;
5
6use crate::PassPolicy;
7
8/// Conditionally remove some of the VarDebugInfo in MIR.
9///
10/// In particular, stripping non-parameter debug info for tiny, primitive-like
11/// methods in core saves work later, and nobody ever wanted to use it anyway.
12pub(super) struct StripDebugInfo;
13
14impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
15 fn policy(&self, ctx: &crate::PassCtx<'_>) -> PassPolicy {
16 PassPolicy::optional(ctx.opts.unstable_opts.mir_strip_debuginfo != MirStripDebugInfo::None)
17 }
18
19 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
20 match tcx.sess.opts.unstable_opts.mir_strip_debuginfo {
21 MirStripDebugInfo::None => return,
22 MirStripDebugInfo::AllLocals => {}
23 MirStripDebugInfo::LocalsInTinyFunctions
24 if let TerminatorKind::Return { .. } =
25 body.basic_blocks[START_BLOCK].terminator().kind => {}
26 MirStripDebugInfo::LocalsInTinyFunctions => return,
27 }
28
29 body.var_debug_info.retain(|vdi| {
30 matches!(
31 vdi.value,
32 VarDebugInfoContents::Place(place)
33 if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE,
34 )
35 });
36
37 drop_invalid_debuginfos(body);
38 }
39}
40
41// Drop invalid debuginfos when strip locals in `var_debug_info`.
42pub(super) fn drop_invalid_debuginfos(body: &mut Body<'_>) {
43 let debuginfo_locals = debuginfo_locals(body);
44 for data in body.basic_blocks.as_mut_preserves_cfg() {
45 for stmt in data.statements.iter_mut() {
46 stmt.debuginfos.retain_locals(&debuginfo_locals);
47 }
48 data.after_last_stmt_debuginfos.retain_locals(&debuginfo_locals);
49 }
50}