33
44use  rustc:: hir:: def:: DefKind ; 
55use  rustc:: mir:: { 
6-     Constant ,  Location ,  Place ,  PlaceBase ,  Mir ,  Operand ,  Rvalue ,  Local , 
6+     AggregateKind ,   Constant ,  Location ,  Place ,  PlaceBase ,  Mir ,  Operand ,  Rvalue ,  Local , 
77    NullOp ,  UnOp ,  StatementKind ,  Statement ,  LocalKind ,  Static ,  StaticKind , 
88    TerminatorKind ,  Terminator ,   ClearCrossCrate ,  SourceInfo ,  BinOp ,  ProjectionElem , 
99    SourceScope ,  SourceScopeLocalData ,  LocalDecl ,  Promoted , 
1010} ; 
11- use  rustc:: mir:: visit:: { Visitor ,  PlaceContext ,  MutatingUseContext ,  NonMutatingUseContext } ; 
11+ use  rustc:: mir:: visit:: { 
12+     Visitor ,  PlaceContext ,  MutatingUseContext ,  MutVisitor ,  NonMutatingUseContext , 
13+ } ; 
1214use  rustc:: mir:: interpret:: { InterpError ,  Scalar ,  GlobalId ,  EvalResult } ; 
1315use  rustc:: ty:: { self ,  Instance ,  ParamEnv ,  Ty ,  TyCtxt } ; 
1416use  syntax:: source_map:: DUMMY_SP ; 
@@ -19,7 +21,7 @@ use rustc::ty::layout::{
1921    HasTyCtxt ,  TargetDataLayout ,  HasDataLayout , 
2022} ; 
2123
22- use  crate :: interpret:: { InterpretCx ,  ScalarMaybeUndef ,  Immediate ,  OpTy ,  ImmTy ,  MemoryKind } ; 
24+ use  crate :: interpret:: { self ,   InterpretCx ,  ScalarMaybeUndef ,  Immediate ,  OpTy ,  ImmTy ,  MemoryKind } ; 
2325use  crate :: const_eval:: { 
2426    CompileTimeInterpreter ,  error_to_const_error,  eval_promoted,  mk_eval_cx, 
2527} ; 
@@ -497,6 +499,50 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
497499            } , 
498500        } 
499501    } 
502+ 
503+     fn  operand_from_scalar ( & self ,  scalar :  Scalar ,  ty :  Ty < ' tcx > )  -> Operand < ' tcx >  { 
504+         Operand :: Constant ( Box :: new ( 
505+             Constant  { 
506+                 span :  DUMMY_SP , 
507+                 ty, 
508+                 user_ty :  None , 
509+                 literal :  self . tcx . mk_const ( ty:: Const :: from_scalar ( 
510+                     scalar, 
511+                     ty, 
512+                 ) ) 
513+             } 
514+         ) ) 
515+     } 
516+ 
517+     fn  replace_with_const ( & self ,  rval :  & mut  Rvalue < ' tcx > ,  value :  Const < ' tcx > )  { 
518+         if  let  interpret:: Operand :: Immediate ( im)  = * value { 
519+             match  im { 
520+                 interpret:: Immediate :: Scalar ( ScalarMaybeUndef :: Scalar ( scalar) )  => { 
521+                     * rval = Rvalue :: Use ( self . operand_from_scalar ( scalar,  value. layout . ty ) ) ; 
522+                 } , 
523+                 Immediate :: ScalarPair ( 
524+                     ScalarMaybeUndef :: Scalar ( one) , 
525+                     ScalarMaybeUndef :: Scalar ( two) 
526+                 )  => { 
527+                     let  ty = & value. layout . ty . sty ; 
528+                     if  let  ty:: Tuple ( substs)  = ty { 
529+                         * rval = Rvalue :: Aggregate ( 
530+                             Box :: new ( AggregateKind :: Tuple ) , 
531+                             vec ! [ 
532+                                 self . operand_from_scalar( one,  substs[ 0 ] . expect_ty( ) ) , 
533+                                 self . operand_from_scalar( two,  substs[ 1 ] . expect_ty( ) ) , 
534+                             ] , 
535+                         ) ; 
536+                     } 
537+                 } , 
538+                 _ => {  } 
539+             } 
540+         } 
541+     } 
542+ 
543+     fn  should_const_prop ( & self )  -> bool  { 
544+         true 
545+     } 
500546} 
501547
502548fn  type_size_of < ' a ,  ' tcx > ( tcx :  TyCtxt < ' a ,  ' tcx ,  ' tcx > , 
@@ -560,10 +606,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
560606    } 
561607} 
562608
563- impl < ' b ,  ' a ,  ' tcx >  Visitor < ' tcx >  for  ConstPropagator < ' b ,  ' a ,  ' tcx >  { 
609+ impl < ' b ,  ' a ,  ' tcx >  MutVisitor < ' tcx >  for  ConstPropagator < ' b ,  ' a ,  ' tcx >  { 
564610    fn  visit_constant ( 
565611        & mut  self , 
566-         constant :  & Constant < ' tcx > , 
612+         constant :  & mut   Constant < ' tcx > , 
567613        location :  Location , 
568614    )  { 
569615        trace ! ( "visit_constant: {:?}" ,  constant) ; 
@@ -573,11 +619,11 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
573619
574620    fn  visit_statement ( 
575621        & mut  self , 
576-         statement :  & Statement < ' tcx > , 
622+         statement :  & mut   Statement < ' tcx > , 
577623        location :  Location , 
578624    )  { 
579625        trace ! ( "visit_statement: {:?}" ,  statement) ; 
580-         if  let  StatementKind :: Assign ( ref  place,  ref  rval)  = statement. kind  { 
626+         if  let  StatementKind :: Assign ( ref  place,  ref  mut   rval)  = statement. kind  { 
581627            let  place_ty:  Ty < ' tcx >  = place
582628                . ty ( & self . local_decls ,  self . tcx ) 
583629                . ty ; 
@@ -589,6 +635,10 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
589635                            trace ! ( "storing {:?} to {:?}" ,  value,  local) ; 
590636                            assert ! ( self . places[ local] . is_none( ) ) ; 
591637                            self . places [ local]  = Some ( value) ; 
638+ 
639+                             if  self . should_const_prop ( )  { 
640+                                 self . replace_with_const ( rval,  value) ; 
641+                             } 
592642                        } 
593643                    } 
594644                } 
@@ -599,79 +649,111 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
599649
600650    fn  visit_terminator ( 
601651        & mut  self , 
602-         terminator :  & Terminator < ' tcx > , 
652+         terminator :  & mut   Terminator < ' tcx > , 
603653        location :  Location , 
604654    )  { 
605655        self . super_terminator ( terminator,  location) ; 
606-         let  source_info = terminator. source_info ; ; 
607-         if  let  TerminatorKind :: Assert  {  expected,  msg,  cond,  .. }  = & terminator. kind  { 
608-             if  let  Some ( value)  = self . eval_operand ( & cond,  source_info)  { 
609-                 trace ! ( "assertion on {:?} should be {:?}" ,  value,  expected) ; 
610-                 let  expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ; 
611-                 if  expected != self . ecx . read_scalar ( value) . unwrap ( )  { 
612-                     // poison all places this operand references so that further code 
613-                     // doesn't use the invalid value 
614-                     match  cond { 
615-                         Operand :: Move ( ref  place)  | Operand :: Copy ( ref  place)  => { 
616-                             let  mut  place = place; 
617-                             while  let  Place :: Projection ( ref  proj)  = * place { 
618-                                 place = & proj. base ; 
619-                             } 
620-                             if  let  Place :: Base ( PlaceBase :: Local ( local) )  = * place { 
621-                                 self . places [ local]  = None ; 
656+         let  source_info = terminator. source_info ; 
657+         match  & mut  terminator. kind  { 
658+             TerminatorKind :: Assert  {  expected,  msg,  ref  mut  cond,  .. }  => { 
659+                 if  let  Some ( value)  = self . eval_operand ( & cond,  source_info)  { 
660+                     trace ! ( "assertion on {:?} should be {:?}" ,  value,  expected) ; 
661+                     let  expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ; 
662+                     let  value_const = self . ecx . read_scalar ( value) . unwrap ( ) ; 
663+                     if  expected != value_const { 
664+                         // poison all places this operand references so that further code 
665+                         // doesn't use the invalid value 
666+                         match  cond { 
667+                             Operand :: Move ( ref  place)  | Operand :: Copy ( ref  place)  => { 
668+                                 let  mut  place = place; 
669+                                 while  let  Place :: Projection ( ref  proj)  = * place { 
670+                                     place = & proj. base ; 
671+                                 } 
672+                                 if  let  Place :: Base ( PlaceBase :: Local ( local) )  = * place { 
673+                                     self . places [ local]  = None ; 
674+                                 } 
675+                             } , 
676+                             Operand :: Constant ( _)  => { } 
677+                         } 
678+                         let  span = terminator. source_info . span ; 
679+                         let  hir_id = self 
680+                             . tcx 
681+                             . hir ( ) 
682+                             . as_local_hir_id ( self . source . def_id ( ) ) 
683+                             . expect ( "some part of a failing const eval must be local" ) ; 
684+                         use  rustc:: mir:: interpret:: InterpError :: * ; 
685+                         let  msg = match  msg { 
686+                             Overflow ( _)  |
687+                             OverflowNeg  |
688+                             DivisionByZero  |
689+                             RemainderByZero  => msg. description ( ) . to_owned ( ) , 
690+                             BoundsCheck  {  ref  len,  ref  index }  => { 
691+                                 let  len = self 
692+                                     . eval_operand ( len,  source_info) 
693+                                     . expect ( "len must be const" ) ; 
694+                                 let  len = match  self . ecx . read_scalar ( len)  { 
695+                                     Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits  { 
696+                                         bits,  ..
697+                                     } ) )  => bits, 
698+                                     other => bug ! ( "const len not primitive: {:?}" ,  other) , 
699+                                 } ; 
700+                                 let  index = self 
701+                                     . eval_operand ( index,  source_info) 
702+                                     . expect ( "index must be const" ) ; 
703+                                 let  index = match  self . ecx . read_scalar ( index)  { 
704+                                     Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits  { 
705+                                         bits,  ..
706+                                     } ) )  => bits, 
707+                                     other => bug ! ( "const index not primitive: {:?}" ,  other) , 
708+                                 } ; 
709+                                 format ! ( 
710+                                     "index out of bounds: \  
711+                                      the len is {} but the index is {}", 
712+                                     len, 
713+                                     index, 
714+                                 ) 
715+                             } , 
716+                             // Need proper const propagator for these 
717+                             _ => return , 
718+                         } ; 
719+                         self . tcx . lint_hir ( 
720+                             :: rustc:: lint:: builtin:: CONST_ERR , 
721+                             hir_id, 
722+                             span, 
723+                             & msg, 
724+                         ) ; 
725+                     }  else  { 
726+                         if  self . should_const_prop ( )  { 
727+                             if  let  ScalarMaybeUndef :: Scalar ( scalar)  = value_const { 
728+                                 * cond = self . operand_from_scalar ( scalar,  self . tcx . types . bool ) ; 
622729                            } 
623-                         } , 
624-                         Operand :: Constant ( _)  => { } 
730+                         } 
625731                    } 
626-                     let  span = terminator. source_info . span ; 
627-                     let  hir_id = self 
628-                         . tcx 
629-                         . hir ( ) 
630-                         . as_local_hir_id ( self . source . def_id ( ) ) 
631-                         . expect ( "some part of a failing const eval must be local" ) ; 
632-                     use  rustc:: mir:: interpret:: InterpError :: * ; 
633-                     let  msg = match  msg { 
634-                         Overflow ( _)  |
635-                         OverflowNeg  |
636-                         DivisionByZero  |
637-                         RemainderByZero  => msg. description ( ) . to_owned ( ) , 
638-                         BoundsCheck  {  ref  len,  ref  index }  => { 
639-                             let  len = self 
640-                                 . eval_operand ( len,  source_info) 
641-                                 . expect ( "len must be const" ) ; 
642-                             let  len = match  self . ecx . read_scalar ( len)  { 
643-                                 Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits  { 
644-                                     bits,  ..
645-                                 } ) )  => bits, 
646-                                 other => bug ! ( "const len not primitive: {:?}" ,  other) , 
647-                             } ; 
648-                             let  index = self 
649-                                 . eval_operand ( index,  source_info) 
650-                                 . expect ( "index must be const" ) ; 
651-                             let  index = match  self . ecx . read_scalar ( index)  { 
652-                                 Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits  { 
653-                                     bits,  ..
654-                                 } ) )  => bits, 
655-                                 other => bug ! ( "const index not primitive: {:?}" ,  other) , 
656-                             } ; 
657-                             format ! ( 
658-                                 "index out of bounds: \  
659-                                  the len is {} but the index is {}", 
660-                                 len, 
661-                                 index, 
662-                             ) 
663-                         } , 
664-                         // Need proper const propagator for these 
665-                         _ => return , 
666-                     } ; 
667-                     self . tcx . lint_hir ( 
668-                         :: rustc:: lint:: builtin:: CONST_ERR , 
669-                         hir_id, 
670-                         span, 
671-                         & msg, 
672-                     ) ; 
673732                } 
674-             } 
733+             } , 
734+             TerminatorKind :: SwitchInt  {  ref  mut  discr,  switch_ty,  .. }  => { 
735+                 if  self . should_const_prop ( )  { 
736+                     if  let  Some ( value)  = self . eval_operand ( & discr,  source_info)  { 
737+                         if  let  Ok ( ScalarMaybeUndef :: Scalar ( scalar) )  = self . ecx . read_scalar ( value)  { 
738+                             * discr = self . operand_from_scalar ( scalar,  switch_ty) ; 
739+                         } 
740+                     } 
741+                 } 
742+             } , 
743+             //none of these have Operands to const-propagate 
744+             TerminatorKind :: Goto  {  .. }  |
745+             TerminatorKind :: Resume  |
746+             TerminatorKind :: Abort  |
747+             TerminatorKind :: Return  |
748+             TerminatorKind :: Unreachable  |
749+             TerminatorKind :: Drop  {  .. }  |
750+             TerminatorKind :: DropAndReplace  {  .. }  |
751+             TerminatorKind :: Yield  {  .. }  |
752+             TerminatorKind :: GeneratorDrop  |
753+             TerminatorKind :: FalseEdges  {  .. }  |
754+             TerminatorKind :: FalseUnwind  {  .. }  => {  } 
755+             //FIXME(wesleywiser) Call does have Operands that could be const-propagated 
756+             TerminatorKind :: Call  {  .. }  => {  } 
675757        } 
676758    } 
677759} 
0 commit comments