Skip to main content

rustc_mir_transform/
remove_unneeded_drops.rs

1//! This pass replaces a drop of a type that does not need dropping, with a goto.
2//!
3//! When the MIR is built, we check `needs_drop` before emitting a `Drop` for a place. This pass is
4//! useful because (unlike MIR building) it runs after type checking, so it can make use of
5//! `TypingMode::PostAnalysis` to provide more precise type information, especially about opaque
6//! types.
7
8use rustc_middle::mir::*;
9use rustc_middle::ty::TyCtxt;
10use tracing::{debug, trace};
11
12use super::simplify::simplify_cfg;
13use crate::PassPolicy;
14
15pub(super) struct RemoveUnneededDrops;
16
17impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
18    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
19        trace!("Running RemoveUnneededDrops on {:?}", body.source);
20
21        let typing_env = body.typing_env(tcx);
22        let mut should_simplify = false;
23        for block in body.basic_blocks.as_mut() {
24            let terminator = block.terminator_mut();
25            let TerminatorKind::Drop { place, target, .. } = terminator.kind else { continue };
26            let ty = place.ty(&body.local_decls, tcx).ty;
27
28            if ty.needs_drop(tcx, typing_env) {
29                continue;
30            }
31            debug!("SUCCESS: replacing `drop` with goto({:?})", target);
32            terminator.kind = TerminatorKind::Goto { target };
33            should_simplify = true;
34        }
35
36        // if we applied optimizations, we potentially have some cfg to cleanup to
37        // make it easier for further passes
38        if should_simplify {
39            simplify_cfg(tcx, body);
40        }
41    }
42
43    fn policy(&self, _sess: &rustc_session::Session) -> PassPolicy {
44        PassPolicy::optional_non_optimization(true)
45    }
46}