rustc_mir_transform/
remove_zsts.rs1use rustc_middle::mir::visit::*;
4use rustc_middle::mir::*;
5use rustc_middle::ty::{self, Ty, TyCtxt};
6
7pub(super) struct RemoveZsts;
8
9impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
10 fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
11 sess.mir_opt_level() > 0
12 }
13
14 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
15 if tcx.type_of(body.source.def_id()).instantiate_identity().is_coroutine() {
17 return;
18 }
19
20 let typing_env = body.typing_env(tcx);
21 let local_decls = &body.local_decls;
22 let mut replacer = Replacer { tcx, typing_env, local_decls };
23 for var_debug_info in &mut body.var_debug_info {
24 replacer.visit_var_debug_info(var_debug_info);
25 }
26 for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
27 replacer.visit_basic_block_data(bb, data);
28 }
29 }
30
31 fn is_required(&self) -> bool {
32 true
33 }
34}
35
36struct Replacer<'a, 'tcx> {
37 tcx: TyCtxt<'tcx>,
38 typing_env: ty::TypingEnv<'tcx>,
39 local_decls: &'a LocalDecls<'tcx>,
40}
41
42fn trivially_zst<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
48 match ty.kind() {
49 ty::FnDef(..) | ty::Never => Some(true),
51 ty::Tuple(fields) if fields.is_empty() => Some(true),
52 ty::Array(_ty, len) if let Some(0) = len.try_to_target_usize(tcx) => Some(true),
53 ty::Bool
55 | ty::Char
56 | ty::Int(..)
57 | ty::Uint(..)
58 | ty::Float(..)
59 | ty::RawPtr(..)
60 | ty::Ref(..)
61 | ty::FnPtr(..) => Some(false),
62 ty::Coroutine(def_id, _) => {
63 if tcx.is_async_drop_in_place_coroutine(*def_id) { Some(false) } else { None }
66 }
67 _ => None,
69 }
70}
71
72impl<'tcx> Replacer<'_, 'tcx> {
73 fn known_to_be_zst(&self, ty: Ty<'tcx>) -> bool {
74 if let Some(is_zst) = trivially_zst(ty, self.tcx) {
75 is_zst
76 } else {
77 self.tcx
78 .layout_of(self.typing_env.as_query_input(ty))
79 .is_ok_and(|layout| layout.is_zst())
80 }
81 }
82
83 fn make_zst(&self, ty: Ty<'tcx>) -> ConstOperand<'tcx> {
84 debug_assert!(self.known_to_be_zst(ty));
85 ConstOperand {
86 span: rustc_span::DUMMY_SP,
87 user_ty: None,
88 const_: Const::Val(ConstValue::ZeroSized, ty),
89 }
90 }
91}
92
93impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
94 fn tcx(&self) -> TyCtxt<'tcx> {
95 self.tcx
96 }
97
98 fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
99 match var_debug_info.value {
100 VarDebugInfoContents::Const(_) => {}
101 VarDebugInfoContents::Place(place) => {
102 let place_ty = place.ty(self.local_decls, self.tcx).ty;
103 if self.known_to_be_zst(place_ty) {
104 var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty))
105 }
106 }
107 }
108 }
109
110 fn visit_operand(&mut self, operand: &mut Operand<'tcx>, _: Location) {
111 if let Operand::Constant(_) = operand {
112 return;
113 }
114 let op_ty = operand.ty(self.local_decls, self.tcx);
115 if self.known_to_be_zst(op_ty) {
116 *operand = Operand::Constant(Box::new(self.make_zst(op_ty)))
117 }
118 }
119
120 fn visit_statement(&mut self, statement: &mut Statement<'tcx>, loc: Location) {
121 let place_for_ty = match statement.kind {
122 StatementKind::Assign(box (place, ref rvalue)) => {
123 rvalue.is_safe_to_remove().then_some(place)
124 }
125 StatementKind::Deinit(box place)
126 | StatementKind::SetDiscriminant { box place, variant_index: _ }
127 | StatementKind::AscribeUserType(box (place, _), _)
128 | StatementKind::Retag(_, box place)
129 | StatementKind::PlaceMention(box place)
130 | StatementKind::FakeRead(box (_, place)) => Some(place),
131 StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
132 Some(local.into())
133 }
134 StatementKind::Coverage(_)
135 | StatementKind::Intrinsic(_)
136 | StatementKind::Nop
137 | StatementKind::BackwardIncompatibleDropHint { .. }
138 | StatementKind::ConstEvalCounter => None,
139 };
140 if let Some(place_for_ty) = place_for_ty
141 && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty
142 && self.known_to_be_zst(ty)
143 {
144 statement.make_nop();
145 } else {
146 self.super_statement(statement, loc);
147 }
148 }
149}