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