@@ -13,11 +13,7 @@ use rustc_index::vec::IndexVec;
1313use  rustc_middle:: mir:: visit:: { 
1414    MutVisitor ,  MutatingUseContext ,  NonMutatingUseContext ,  PlaceContext ,  Visitor , 
1515} ; 
16- use  rustc_middle:: mir:: { 
17-     BasicBlock ,  BinOp ,  Body ,  Constant ,  ConstantKind ,  Local ,  LocalDecl ,  LocalKind ,  Location , 
18-     Operand ,  Place ,  Rvalue ,  SourceInfo ,  Statement ,  StatementKind ,  Terminator ,  TerminatorKind , 
19-     RETURN_PLACE , 
20- } ; 
16+ use  rustc_middle:: mir:: * ; 
2117use  rustc_middle:: ty:: layout:: { LayoutError ,  LayoutOf ,  LayoutOfHelpers ,  TyAndLayout } ; 
2218use  rustc_middle:: ty:: InternalSubsts ; 
2319use  rustc_middle:: ty:: { self ,  ConstKind ,  Instance ,  ParamEnv ,  Ty ,  TyCtxt ,  TypeVisitable } ; 
@@ -456,27 +452,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
456452        } ; 
457453    } 
458454
459-     fn  use_ecx < F ,  T > ( & mut  self ,  f :  F )  -> Option < T > 
460-     where 
461-         F :  FnOnce ( & mut  Self )  -> InterpResult < ' tcx ,  T > , 
462-     { 
463-         match  f ( self )  { 
464-             Ok ( val)  => Some ( val) , 
465-             Err ( error)  => { 
466-                 trace ! ( "InterpCx operation failed: {:?}" ,  error) ; 
467-                 // Some errors shouldn't come up because creating them causes 
468-                 // an allocation, which we should avoid. When that happens, 
469-                 // dedicated error variants should be introduced instead. 
470-                 assert ! ( 
471-                     !error. kind( ) . formatted_string( ) , 
472-                     "const-prop encountered formatting error: {}" , 
473-                     error
474-                 ) ; 
475-                 None 
476-             } 
477-         } 
478-     } 
479- 
480455    /// Returns the value, if any, of evaluating `c`. 
481456     fn  eval_constant ( & mut  self ,  c :  & Constant < ' tcx > )  -> Option < OpTy < ' tcx > >  { 
482457        // FIXME we need to revisit this for #67176 
@@ -491,7 +466,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
491466    /// Returns the value, if any, of evaluating `place`. 
492467     fn  eval_place ( & mut  self ,  place :  Place < ' tcx > )  -> Option < OpTy < ' tcx > >  { 
493468        trace ! ( "eval_place(place={:?})" ,  place) ; 
494-         self . use_ecx ( |this| this . ecx . eval_place_to_op ( place,  None ) ) 
469+         self . ecx . eval_place_to_op ( place,  None ) . ok ( ) 
495470    } 
496471
497472    /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` 
@@ -595,52 +570,54 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
595570        rvalue :  & Rvalue < ' tcx > , 
596571        place :  Place < ' tcx > , 
597572    )  -> Option < ( ) >  { 
598-         self . use_ecx ( |this|  match  rvalue { 
573+         match  rvalue { 
599574            Rvalue :: BinaryOp ( op,  box ( left,  right) ) 
600575            | Rvalue :: CheckedBinaryOp ( op,  box ( left,  right) )  => { 
601-                 let  l = this . ecx . eval_operand ( left,  None ) . and_then ( |x| this . ecx . read_immediate ( & x) ) ; 
576+                 let  l = self . ecx . eval_operand ( left,  None ) . and_then ( |x| self . ecx . read_immediate ( & x) ) ; 
602577                let  r =
603-                     this . ecx . eval_operand ( right,  None ) . and_then ( |x| this . ecx . read_immediate ( & x) ) ; 
578+                     self . ecx . eval_operand ( right,  None ) . and_then ( |x| self . ecx . read_immediate ( & x) ) ; 
604579
605580                let  const_arg = match  ( l,  r)  { 
606581                    ( Ok ( x) ,  Err ( _) )  | ( Err ( _) ,  Ok ( x) )  => x,  // exactly one side is known 
607-                     ( Err ( e ) ,  Err ( _) )  => return  Err ( e ) ,       // neither side is known 
608-                     ( Ok ( _) ,  Ok ( _) )  => return  this . ecx . eval_rvalue_into_place ( rvalue,  place) ,  // both sides are known 
582+                     ( Err ( _ ) ,  Err ( _) )  => return  None ,          // neither side is known 
583+                     ( Ok ( _) ,  Ok ( _) )  => return  self . ecx . eval_rvalue_into_place ( rvalue,  place) . ok ( ) ,  // both sides are known 
609584                } ; 
610585
611586                if  !matches ! ( const_arg. layout. abi,  abi:: Abi :: Scalar ( ..) )  { 
612587                    // We cannot handle Scalar Pair stuff. 
613588                    // No point in calling `eval_rvalue_into_place`, since only one side is known 
614-                     throw_machine_stop_str ! ( "cannot optimize this" ) 
589+                     return   None ; 
615590                } 
616591
617-                 let  arg_value = const_arg. to_scalar ( ) . to_bits ( const_arg. layout . size ) ?; 
618-                 let  dest = this . ecx . eval_place ( place) ?; 
592+                 let  arg_value = const_arg. to_scalar ( ) . to_bits ( const_arg. layout . size ) . ok ( ) ?; 
593+                 let  dest = self . ecx . eval_place ( place) . ok ( ) ?; 
619594
620595                match  op { 
621-                     BinOp :: BitAnd  if  arg_value == 0  => this. ecx . write_immediate ( * const_arg,  & dest) , 
596+                     BinOp :: BitAnd  if  arg_value == 0  => { 
597+                         self . ecx . write_immediate ( * const_arg,  & dest) . ok ( ) 
598+                     } 
622599                    BinOp :: BitOr 
623600                        if  arg_value == const_arg. layout . size . truncate ( u128:: MAX ) 
624601                            || ( const_arg. layout . ty . is_bool ( )  && arg_value == 1 )  =>
625602                    { 
626-                         this . ecx . write_immediate ( * const_arg,  & dest) 
603+                         self . ecx . write_immediate ( * const_arg,  & dest) . ok ( ) 
627604                    } 
628605                    BinOp :: Mul  if  const_arg. layout . ty . is_integral ( )  && arg_value == 0  => { 
629606                        if  let  Rvalue :: CheckedBinaryOp ( _,  _)  = rvalue { 
630607                            let  val = Immediate :: ScalarPair ( 
631608                                const_arg. to_scalar ( ) , 
632609                                Scalar :: from_bool ( false ) , 
633610                            ) ; 
634-                             this . ecx . write_immediate ( val,  & dest) 
611+                             self . ecx . write_immediate ( val,  & dest) . ok ( ) 
635612                        }  else  { 
636-                             this . ecx . write_immediate ( * const_arg,  & dest) 
613+                             self . ecx . write_immediate ( * const_arg,  & dest) . ok ( ) 
637614                        } 
638615                    } 
639-                     _ => throw_machine_stop_str ! ( "cannot optimize this" ) , 
616+                     _ => None , 
640617                } 
641618            } 
642-             _ => this . ecx . eval_rvalue_into_place ( rvalue,  place) , 
643-         } ) 
619+             _ => self . ecx . eval_rvalue_into_place ( rvalue,  place) . ok ( ) , 
620+         } 
644621    } 
645622
646623    /// Creates a new `Operand::Constant` from a `Scalar` value 
@@ -682,7 +659,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
682659        } 
683660
684661        // FIXME> figure out what to do when read_immediate_raw fails 
685-         let  imm = self . use_ecx ( |this| this . ecx . read_immediate_raw ( value) ) ; 
662+         let  imm = self . ecx . read_immediate_raw ( value) . ok ( ) ; 
686663
687664        if  let  Some ( Right ( imm) )  = imm { 
688665            match  * imm { 
@@ -702,25 +679,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
702679                    if  let  ty:: Tuple ( types)  = ty. kind ( )  { 
703680                        // Only do it if tuple is also a pair with two scalars 
704681                        if  let  [ ty1,  ty2]  = types[ ..]  { 
705-                             let  alloc = self . use_ecx ( |this| { 
706-                                 let  ty_is_scalar = |ty| { 
707-                                     this. ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) ) 
708-                                         == Some ( true ) 
709-                                 } ; 
710-                                 if  ty_is_scalar ( ty1)  && ty_is_scalar ( ty2)  { 
711-                                     let  alloc = this
712-                                         . ecx 
713-                                         . intern_with_temp_alloc ( value. layout ,  |ecx,  dest| { 
714-                                             ecx. write_immediate ( * imm,  dest) 
715-                                         } ) 
716-                                         . unwrap ( ) ; 
717-                                     Ok ( Some ( alloc) ) 
718-                                 }  else  { 
719-                                     Ok ( None ) 
720-                                 } 
721-                             } ) ; 
722- 
723-                             if  let  Some ( Some ( alloc) )  = alloc { 
682+                             let  ty_is_scalar = |ty| { 
683+                                 self . ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) ) 
684+                                     == Some ( true ) 
685+                             } ; 
686+                             let  alloc = if  ty_is_scalar ( ty1)  && ty_is_scalar ( ty2)  { 
687+                                 let  alloc = self 
688+                                     . ecx 
689+                                     . intern_with_temp_alloc ( value. layout ,  |ecx,  dest| { 
690+                                         ecx. write_immediate ( * imm,  dest) 
691+                                     } ) 
692+                                     . unwrap ( ) ; 
693+                                 Some ( alloc) 
694+                             }  else  { 
695+                                 None 
696+                             } ; 
697+ 
698+                             if  let  Some ( alloc)  = alloc { 
724699                                // Assign entire constant in a single statement. 
725700                                // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`. 
726701                                let  const_val = ConstValue :: ByRef  {  alloc,  offset :  Size :: ZERO  } ; 
@@ -921,84 +896,80 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
921896        trace ! ( "visit_statement: {:?}" ,  statement) ; 
922897        let  source_info = statement. source_info ; 
923898        self . source_info  = Some ( source_info) ; 
924-         if  let  StatementKind :: Assign ( box ( place,  ref  mut  rval) )  = statement. kind  { 
925-             let  can_const_prop = self . ecx . machine . can_const_prop [ place. local ] ; 
926-             if  let  Some ( ( ) )  = self . const_prop ( rval,  place)  { 
927-                 // This will return None if the above `const_prop` invocation only "wrote" a 
928-                 // type whose creation requires no write. E.g. a generator whose initial state 
929-                 // consists solely of uninitialized memory (so it doesn't capture any locals). 
930-                 if  let  Some ( ref  value)  = self . get_const ( place)  && self . should_const_prop ( value)  { 
931-                     trace ! ( "replacing {:?} with {:?}" ,  rval,  value) ; 
932-                     self . replace_with_const ( rval,  value,  source_info) ; 
933-                     if  can_const_prop == ConstPropMode :: FullConstProp 
934-                         || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock 
935-                     { 
936-                         trace ! ( "propagated into {:?}" ,  place) ; 
899+         match  statement. kind  { 
900+             StatementKind :: Assign ( box ( place,  ref  mut  rval) )  => { 
901+                 let  can_const_prop = self . ecx . machine . can_const_prop [ place. local ] ; 
902+                 if  let  Some ( ( ) )  = self . const_prop ( rval,  place)  { 
903+                     // This will return None if the above `const_prop` invocation only "wrote" a 
904+                     // type whose creation requires no write. E.g. a generator whose initial state 
905+                     // consists solely of uninitialized memory (so it doesn't capture any locals). 
906+                     if  let  Some ( ref  value)  = self . get_const ( place)  && self . should_const_prop ( value)  { 
907+                         trace ! ( "replacing {:?} with {:?}" ,  rval,  value) ; 
908+                         self . replace_with_const ( rval,  value,  source_info) ; 
909+                         if  can_const_prop == ConstPropMode :: FullConstProp 
910+                             || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock 
911+                         { 
912+                             trace ! ( "propagated into {:?}" ,  place) ; 
913+                         } 
937914                    } 
938-                 } 
939-                 match  can_const_prop { 
940-                     ConstPropMode :: OnlyInsideOwnBlock  => { 
941-                         trace ! ( 
942-                             "found local restricted to its block. \  
915+                     match  can_const_prop { 
916+                         ConstPropMode :: OnlyInsideOwnBlock  => { 
917+                             trace ! ( 
918+                                 "found local restricted to its block. \  
943919                                 Will remove it from const-prop after block is finished. Local: {:?}", 
944-                             place. local
945-                         ) ; 
946-                     } 
947-                     ConstPropMode :: OnlyPropagateInto  | ConstPropMode :: NoPropagation  => { 
948-                         trace ! ( "can't propagate into {:?}" ,  place) ; 
949-                         if  place. local  != RETURN_PLACE  { 
950-                             Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
920+                                 place. local
921+                             ) ; 
951922                        } 
952-                     } 
953-                     ConstPropMode :: FullConstProp  => { } 
954-                 } 
955-             }  else  { 
956-                 // Const prop failed, so erase the destination, ensuring that whatever happens 
957-                 // from here on, does not know about the previous value. 
958-                 // This is important in case we have 
959-                 // ```rust 
960-                 // let mut x = 42; 
961-                 // x = SOME_MUTABLE_STATIC; 
962-                 // // x must now be uninit 
963-                 // ``` 
964-                 // FIXME: we overzealously erase the entire local, because that's easier to 
965-                 // implement. 
966-                 trace ! ( 
967-                     "propagation into {:?} failed. 
968-                         Nuking the entire site from orbit, it's the only way to be sure" , 
969-                     place, 
970-                 ) ; 
971-                 Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
972-             } 
973-         }  else  { 
974-             match  statement. kind  { 
975-                 StatementKind :: SetDiscriminant  {  ref  place,  .. }  => { 
976-                     match  self . ecx . machine . can_const_prop [ place. local ]  { 
977-                         ConstPropMode :: FullConstProp  | ConstPropMode :: OnlyInsideOwnBlock  => { 
978-                             if  self . use_ecx ( |this| this. ecx . statement ( statement) ) . is_some ( )  { 
979-                                 trace ! ( "propped discriminant into {:?}" ,  place) ; 
980-                             }  else  { 
923+                         ConstPropMode :: OnlyPropagateInto  | ConstPropMode :: NoPropagation  => { 
924+                             trace ! ( "can't propagate into {:?}" ,  place) ; 
925+                             if  place. local  != RETURN_PLACE  { 
981926                                Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
982927                            } 
983928                        } 
984-                         ConstPropMode :: OnlyPropagateInto  | ConstPropMode :: NoPropagation  => { 
985-                             Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
986-                         } 
929+                         ConstPropMode :: FullConstProp  => { } 
987930                    } 
931+                 }  else  { 
932+                     // Const prop failed, so erase the destination, ensuring that whatever happens 
933+                     // from here on, does not know about the previous value. 
934+                     // This is important in case we have 
935+                     // ```rust 
936+                     // let mut x = 42; 
937+                     // x = SOME_MUTABLE_STATIC; 
938+                     // // x must now be uninit 
939+                     // ``` 
940+                     // FIXME: we overzealously erase the entire local, because that's easier to 
941+                     // implement. 
942+                     trace ! ( 
943+                         "propagation into {:?} failed. 
944+                         Nuking the entire site from orbit, it's the only way to be sure" , 
945+                         place, 
946+                     ) ; 
947+                     Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
988948                } 
989-                 StatementKind :: StorageLive ( local)  | StatementKind :: StorageDead ( local)  => { 
990-                     let  frame = self . ecx . frame_mut ( ) ; 
991-                     frame. locals [ local] . value  =
992-                         if  let  StatementKind :: StorageLive ( _)  = statement. kind  { 
993-                             LocalValue :: Live ( interpret:: Operand :: Immediate ( 
994-                                 interpret:: Immediate :: Uninit , 
995-                             ) ) 
949+             } 
950+             StatementKind :: SetDiscriminant  {  ref  place,  .. }  => { 
951+                 match  self . ecx . machine . can_const_prop [ place. local ]  { 
952+                     ConstPropMode :: FullConstProp  | ConstPropMode :: OnlyInsideOwnBlock  => { 
953+                         if  self . ecx . statement ( statement) . is_ok ( )  { 
954+                             trace ! ( "propped discriminant into {:?}" ,  place) ; 
996955                        }  else  { 
997-                             LocalValue :: Dead 
998-                         } ; 
956+                             Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
957+                         } 
958+                     } 
959+                     ConstPropMode :: OnlyPropagateInto  | ConstPropMode :: NoPropagation  => { 
960+                         Self :: remove_const ( & mut  self . ecx ,  place. local ) ; 
961+                     } 
999962                } 
1000-                 _ => { } 
1001963            } 
964+             StatementKind :: StorageLive ( local)  | StatementKind :: StorageDead ( local)  => { 
965+                 let  frame = self . ecx . frame_mut ( ) ; 
966+                 frame. locals [ local] . value  = if  let  StatementKind :: StorageLive ( _)  = statement. kind  { 
967+                     LocalValue :: Live ( interpret:: Operand :: Immediate ( interpret:: Immediate :: Uninit ) ) 
968+                 }  else  { 
969+                     LocalValue :: Dead 
970+                 } ; 
971+             } 
972+             _ => { } 
1002973        } 
1003974
1004975        self . super_statement ( statement,  location) ; 
@@ -1008,12 +979,10 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
1008979        let  source_info = terminator. source_info ; 
1009980        self . source_info  = Some ( source_info) ; 
1010981        self . super_terminator ( terminator,  location) ; 
1011-          // Do NOT early return in this function, it does some crucial fixup of the state at the end! 
982+ 
1012983        match  & mut  terminator. kind  { 
1013984            TerminatorKind :: Assert  {  expected,  ref  mut  cond,  .. }  => { 
1014985                if  let  Some ( ref  value)  = self . eval_operand ( & cond) 
1015-                     // FIXME should be used use_ecx rather than a local match... but we have 
1016-                     // quite a few of these read_scalar/read_immediate that need fixing. 
1017986                    && let  Ok ( value_const)  = self . ecx . read_scalar ( & value) 
1018987                    && self . should_const_prop ( value) 
1019988                { 
@@ -1050,6 +1019,10 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
10501019            // gated on `mir_opt_level=3`. 
10511020            TerminatorKind :: Call  {  .. }  => { } 
10521021        } 
1022+     } 
1023+ 
1024+     fn  visit_basic_block_data ( & mut  self ,  block :  BasicBlock ,  data :  & mut  BasicBlockData < ' tcx > )  { 
1025+         self . super_basic_block_data ( block,  data) ; 
10531026
10541027        // We remove all Locals which are restricted in propagation to their containing blocks and 
10551028        // which were modified in the current block. 
0 commit comments