frontend 0.4.0

rustc's frontend with no LLVM and no std: parsing through MIR, as a library
// `#![no_std]`: these arrive with the standard prelude and name no path, so a `std::`
// search cannot see them - and a `#[derive]` can use them without the name appearing
// in this file at all, which is why they are not trimmed by inspection.
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;

use crate::rustc_middle::mir::*;
use crate::rustc_middle::ty::TyCtxt;
use crate::rustc_mir_dataflow::debuginfo::debuginfo_locals;
use crate::rustc_session::config::MirStripDebugInfo;

use crate::rustc_mir_transform::PassPolicy;

/// Conditionally remove some of the VarDebugInfo in MIR.
///
/// In particular, stripping non-parameter debug info for tiny, primitive-like
/// methods in core saves work later, and nobody ever wanted to use it anyway.
pub(super) struct StripDebugInfo;

impl<'tcx> crate::rustc_mir_transform::MirPass<'tcx> for StripDebugInfo {
    fn policy(&self, sess: &crate::rustc_session::Session) -> PassPolicy {
        PassPolicy::optional_non_optimization(
            sess.opts.unstable_opts.mir_strip_debuginfo != MirStripDebugInfo::None,
        )
    }

    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        match tcx.sess.opts.unstable_opts.mir_strip_debuginfo {
            MirStripDebugInfo::None => return,
            MirStripDebugInfo::AllLocals => {}
            MirStripDebugInfo::LocalsInTinyFunctions
                if let TerminatorKind::Return { .. } =
                    body.basic_blocks[START_BLOCK].terminator().kind => {}
            MirStripDebugInfo::LocalsInTinyFunctions => return,
        }

        body.var_debug_info.retain(|vdi| {
            matches!(
                vdi.value,
                VarDebugInfoContents::Place(place)
                    if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE,
            )
        });

        drop_invalid_debuginfos(body);
    }
}

// Drop invalid debuginfos when strip locals in `var_debug_info`.
pub(super) fn drop_invalid_debuginfos(body: &mut Body<'_>) {
    let debuginfo_locals = debuginfo_locals(body);
    for data in body.basic_blocks.as_mut_preserves_cfg() {
        for stmt in data.statements.iter_mut() {
            stmt.debuginfos.retain_locals(&debuginfo_locals);
        }
        data.after_last_stmt_debuginfos.retain_locals(&debuginfo_locals);
    }
}