@@ -470,7 +470,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
470
470
}
471
471
}
472
472
473
- fn const_prop ( & mut self , rvalue : & Rvalue < ' tcx > , place : Place < ' tcx > ) -> Option < ( ) > {
473
+ fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < ( ) > {
474
474
// Perform any special handling for specific Rvalue types.
475
475
// Generally, checks here fall into one of two categories:
476
476
// 1. Additional checking to provide useful lints to the user
@@ -527,7 +527,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
527
527
return None ;
528
528
}
529
529
530
- self . eval_rvalue_with_identities ( rvalue , place )
530
+ Some ( ( ) )
531
531
}
532
532
533
533
// Attempt to use algebraic identities to eliminate constant expressions
@@ -595,7 +595,16 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
595
595
} ) )
596
596
}
597
597
598
- fn replace_with_const ( & mut self , rval : & mut Rvalue < ' tcx > , value : & OpTy < ' tcx > ) {
598
+ fn replace_with_const ( & mut self , place : Place < ' tcx > , rval : & mut Rvalue < ' tcx > ) {
599
+ // This will return None if the above `const_prop` invocation only "wrote" a
600
+ // type whose creation requires no write. E.g. a generator whose initial state
601
+ // consists solely of uninitialized memory (so it doesn't capture any locals).
602
+ let Some ( ref value) = self . get_const ( place) else { return } ;
603
+ if !self . should_const_prop ( value) {
604
+ return ;
605
+ }
606
+ trace ! ( "replacing {:?}={:?} with {:?}" , place, rval, value) ;
607
+
599
608
if let Rvalue :: Use ( Operand :: Constant ( c) ) = rval {
600
609
match c. literal {
601
610
ConstantKind :: Ty ( c) if matches ! ( c. kind( ) , ConstKind :: Unevaluated ( ..) ) => { }
@@ -688,6 +697,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
688
697
_ => false ,
689
698
}
690
699
}
700
+
701
+ fn ensure_not_propagated ( & mut self , local : Local ) {
702
+ if cfg ! ( debug_assertions) {
703
+ assert ! (
704
+ self . get_const( local. into( ) ) . is_none( )
705
+ || self
706
+ . layout_of( self . local_decls[ local] . ty)
707
+ . map_or( true , |layout| layout. is_zst( ) ) ,
708
+ "failed to remove values for `{local:?}`, value={:?}" ,
709
+ self . get_const( local. into( ) ) ,
710
+ )
711
+ }
712
+ }
691
713
}
692
714
693
715
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
@@ -827,44 +849,23 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
827
849
self . eval_constant ( constant) ;
828
850
}
829
851
830
- fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
831
- trace ! ( "visit_statement: {:?}" , statement) ;
832
-
833
- // Recurse into statement before applying the assignment.
834
- self . super_statement ( statement, location) ;
835
-
836
- match statement. kind {
837
- StatementKind :: Assign ( box ( place, ref mut rval) ) => {
838
- let can_const_prop = self . ecx . machine . can_const_prop [ place. local ] ;
839
- if let Some ( ( ) ) = self . const_prop ( rval, place) {
840
- // This will return None if the above `const_prop` invocation only "wrote" a
841
- // type whose creation requires no write. E.g. a generator whose initial state
842
- // consists solely of uninitialized memory (so it doesn't capture any locals).
843
- if let Some ( ref value) = self . get_const ( place) && self . should_const_prop ( value) {
844
- trace ! ( "replacing {:?} with {:?}" , rval, value) ;
845
- self . replace_with_const ( rval, value) ;
846
- if can_const_prop == ConstPropMode :: FullConstProp
847
- || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock
848
- {
849
- trace ! ( "propagated into {:?}" , place) ;
850
- }
851
- }
852
- match can_const_prop {
853
- ConstPropMode :: OnlyInsideOwnBlock => {
854
- trace ! (
855
- "found local restricted to its block. \
856
- Will remove it from const-prop after block is finished. Local: {:?}",
857
- place. local
858
- ) ;
859
- }
860
- ConstPropMode :: NoPropagation => {
861
- trace ! ( "can't propagate into {:?}" , place) ;
862
- if place. local != RETURN_PLACE {
863
- Self :: remove_const ( & mut self . ecx , place. local ) ;
864
- }
865
- }
866
- ConstPropMode :: FullConstProp => { }
867
- }
852
+ fn visit_assign (
853
+ & mut self ,
854
+ place : & mut Place < ' tcx > ,
855
+ rvalue : & mut Rvalue < ' tcx > ,
856
+ location : Location ,
857
+ ) {
858
+ self . super_assign ( place, rvalue, location) ;
859
+
860
+ let Some ( ( ) ) = self . check_rvalue ( rvalue) else { return } ;
861
+
862
+ match self . ecx . machine . can_const_prop [ place. local ] {
863
+ // Do nothing if the place is indirect.
864
+ _ if place. is_indirect ( ) => { }
865
+ ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
866
+ ConstPropMode :: OnlyInsideOwnBlock | ConstPropMode :: FullConstProp => {
867
+ if let Some ( ( ) ) = self . eval_rvalue_with_identities ( rvalue, * place) {
868
+ self . replace_with_const ( * place, rvalue) ;
868
869
} else {
869
870
// Const prop failed, so erase the destination, ensuring that whatever happens
870
871
// from here on, does not know about the previous value.
@@ -884,18 +885,28 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
884
885
Self :: remove_const ( & mut self . ecx , place. local ) ;
885
886
}
886
887
}
888
+ }
889
+ }
890
+
891
+ fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
892
+ trace ! ( "visit_statement: {:?}" , statement) ;
893
+
894
+ // Recurse into statement before applying the assignment.
895
+ self . super_statement ( statement, location) ;
896
+
897
+ match statement. kind {
887
898
StatementKind :: SetDiscriminant { ref place, .. } => {
888
899
match self . ecx . machine . can_const_prop [ place. local ] {
900
+ // Do nothing if the place is indirect.
901
+ _ if place. is_indirect ( ) => { }
902
+ ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
889
903
ConstPropMode :: FullConstProp | ConstPropMode :: OnlyInsideOwnBlock => {
890
904
if self . ecx . statement ( statement) . is_ok ( ) {
891
905
trace ! ( "propped discriminant into {:?}" , place) ;
892
906
} else {
893
907
Self :: remove_const ( & mut self . ecx , place. local ) ;
894
908
}
895
909
}
896
- ConstPropMode :: NoPropagation => {
897
- Self :: remove_const ( & mut self . ecx , place. local ) ;
898
- }
899
910
}
900
911
}
901
912
StatementKind :: StorageLive ( local) => {
@@ -958,30 +969,17 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
958
969
fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
959
970
self . super_basic_block_data ( block, data) ;
960
971
961
- let ensure_not_propagated = |this : & mut Self , local : Local | {
962
- if cfg ! ( debug_assertions) {
963
- assert ! (
964
- this. get_const( local. into( ) ) . is_none( )
965
- || this
966
- . layout_of( this. local_decls[ local] . ty)
967
- . map_or( true , |layout| layout. is_zst( ) ) ,
968
- "failed to remove values for `{local:?}`, value={:?}" ,
969
- this. get_const( local. into( ) ) ,
970
- )
971
- }
972
- } ;
973
-
974
972
// We remove all Locals which are restricted in propagation to their containing blocks and
975
973
// which were modified in the current block.
976
974
// Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
977
975
let can_const_prop = std:: mem:: take ( & mut self . ecx . machine . can_const_prop ) ;
978
976
for ( local, & mode) in can_const_prop. iter_enumerated ( ) {
979
977
match mode {
980
978
ConstPropMode :: FullConstProp => { }
981
- ConstPropMode :: NoPropagation => ensure_not_propagated ( self , local) ,
979
+ ConstPropMode :: NoPropagation => self . ensure_not_propagated ( local) ,
982
980
ConstPropMode :: OnlyInsideOwnBlock => {
983
981
Self :: remove_const ( & mut self . ecx , local) ;
984
- ensure_not_propagated ( self , local) ;
982
+ self . ensure_not_propagated ( local) ;
985
983
}
986
984
}
987
985
}
0 commit comments