11//! Removes assignments to ZST places.
22
33use crate :: MirPass ;
4- use rustc_middle:: mir:: { Body , StatementKind } ;
4+ use rustc_middle:: mir:: interpret:: ConstValue ;
5+ use rustc_middle:: mir:: visit:: * ;
6+ use rustc_middle:: mir:: * ;
57use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
68
79pub struct RemoveZsts ;
@@ -16,38 +18,24 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
1618 if tcx. type_of ( body. source . def_id ( ) ) . subst_identity ( ) . is_generator ( ) {
1719 return ;
1820 }
19- let param_env = tcx. param_env ( body. source . def_id ( ) ) ;
20- let basic_blocks = body. basic_blocks . as_mut_preserves_cfg ( ) ;
21+ let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
2122 let local_decls = & body. local_decls ;
22- for block in basic_blocks {
23- for statement in block. statements . iter_mut ( ) {
24- if let StatementKind :: Assign ( box ( place, _) ) | StatementKind :: Deinit ( box place) =
25- statement. kind
26- {
27- let place_ty = place. ty ( local_decls, tcx) . ty ;
28- if !maybe_zst ( place_ty) {
29- continue ;
30- }
31- let Ok ( layout) = tcx. layout_of ( param_env. and ( place_ty) ) else {
32- continue ;
33- } ;
34- if !layout. is_zst ( ) {
35- continue ;
36- }
37- if tcx. consider_optimizing ( || {
38- format ! (
39- "RemoveZsts - Place: {:?} SourceInfo: {:?}" ,
40- place, statement. source_info
41- )
42- } ) {
43- statement. make_nop ( ) ;
44- }
45- }
46- }
23+ let mut replacer = Replacer { tcx, param_env, local_decls } ;
24+ for var_debug_info in & mut body. var_debug_info {
25+ replacer. visit_var_debug_info ( var_debug_info) ;
26+ }
27+ for ( bb, data) in body. basic_blocks . as_mut_preserves_cfg ( ) . iter_enumerated_mut ( ) {
28+ replacer. visit_basic_block_data ( bb, data) ;
4729 }
4830 }
4931}
5032
33+ struct Replacer < ' a , ' tcx > {
34+ tcx : TyCtxt < ' tcx > ,
35+ param_env : ty:: ParamEnv < ' tcx > ,
36+ local_decls : & ' a LocalDecls < ' tcx > ,
37+ }
38+
5139/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
5240fn maybe_zst ( ty : Ty < ' _ > ) -> bool {
5341 match ty. kind ( ) {
@@ -63,3 +51,80 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
6351 _ => false ,
6452 }
6553}
54+
55+ impl < ' tcx > Replacer < ' _ , ' tcx > {
56+ fn is_zst ( & self , ty : Ty < ' tcx > ) -> bool {
57+ if !maybe_zst ( ty) {
58+ return false ;
59+ }
60+ let Ok ( layout) = self . tcx . layout_of ( self . param_env . and ( ty) ) else {
61+ return false ;
62+ } ;
63+ layout. is_zst ( )
64+ }
65+
66+ fn make_zst ( & self , ty : Ty < ' tcx > ) -> Constant < ' tcx > {
67+ debug_assert ! ( self . is_zst( ty) ) ;
68+ Constant {
69+ span : rustc_span:: DUMMY_SP ,
70+ user_ty : None ,
71+ literal : ConstantKind :: Val ( ConstValue :: ZeroSized , ty) ,
72+ }
73+ }
74+ }
75+
76+ impl < ' tcx > MutVisitor < ' tcx > for Replacer < ' _ , ' tcx > {
77+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
78+ self . tcx
79+ }
80+
81+ fn visit_var_debug_info ( & mut self , var_debug_info : & mut VarDebugInfo < ' tcx > ) {
82+ match var_debug_info. value {
83+ VarDebugInfoContents :: Const ( _) => { }
84+ VarDebugInfoContents :: Place ( place) => {
85+ let place_ty = place. ty ( self . local_decls , self . tcx ) . ty ;
86+ if self . is_zst ( place_ty) {
87+ var_debug_info. value = VarDebugInfoContents :: Const ( self . make_zst ( place_ty) )
88+ }
89+ }
90+ VarDebugInfoContents :: Composite { ty, fragments : _ } => {
91+ if self . is_zst ( ty) {
92+ var_debug_info. value = VarDebugInfoContents :: Const ( self . make_zst ( ty) )
93+ }
94+ }
95+ }
96+ }
97+
98+ fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , loc : Location ) {
99+ if let Operand :: Constant ( _) = operand {
100+ return ;
101+ }
102+ let op_ty = operand. ty ( self . local_decls , self . tcx ) ;
103+ if self . is_zst ( op_ty)
104+ && self . tcx . consider_optimizing ( || {
105+ format ! ( "RemoveZsts - Operand: {:?} Location: {:?}" , operand, loc)
106+ } )
107+ {
108+ * operand = Operand :: Constant ( Box :: new ( self . make_zst ( op_ty) ) )
109+ }
110+ }
111+
112+ fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , loc : Location ) {
113+ if let StatementKind :: Assign ( box ( place, _) ) | StatementKind :: Deinit ( box place) =
114+ statement. kind
115+ {
116+ let place_ty = place. ty ( self . local_decls , self . tcx ) . ty ;
117+ if self . is_zst ( place_ty)
118+ && self . tcx . consider_optimizing ( || {
119+ format ! (
120+ "RemoveZsts - Place: {:?} SourceInfo: {:?}" ,
121+ place, statement. source_info
122+ )
123+ } )
124+ {
125+ statement. make_nop ( ) ;
126+ }
127+ }
128+ self . super_statement ( statement, loc) ;
129+ }
130+ }
0 commit comments