rustc_mir_transform/
lower_slice_len.rs1use rustc_hir::def_id::DefId;
5use rustc_middle::mir::*;
6use rustc_middle::ty::TyCtxt;
7
8use crate::PassPolicy;
9
10pub(super) struct LowerSliceLenCalls;
11
12impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
13 fn policy(&self, sess: &rustc_session::Session) -> PassPolicy {
14 PassPolicy::optimization(sess.mir_opt_level() > 0)
15 }
16
17 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
18 let language_items = tcx.lang_items();
19 let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else {
20 return;
22 };
23
24 let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
26 for block in basic_blocks {
27 lower_slice_len_call(block, slice_len_fn_item_def_id);
29 }
30 }
31}
32
33fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {
34 let terminator = block.terminator();
35 if let TerminatorKind::Call {
36 func,
37 args,
38 destination,
39 target: Some(bb),
40 call_source: CallSource::Normal,
41 ..
42 } = &terminator.kind
43 && let [arg] = &args[..]
45 && let Some((fn_def_id, _)) = func.const_fn_def()
46 && fn_def_id == slice_len_fn_item_def_id
47 {
48 let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone());
56 let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value)));
57 let add_statement = Statement::new(terminator.source_info, len_statement_kind);
58
59 let new_terminator_kind = TerminatorKind::Goto { target: *bb };
61
62 block.statements.push(add_statement);
63 block.terminator_mut().kind = new_terminator_kind;
64 }
65}