@@ -546,6 +546,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
546
546
}
547
547
}
548
548
}
549
+
550
+ fn should_const_prop ( & self ) -> bool {
551
+ self . tcx . sess . opts . debugging_opts . mir_opt_level >= 2
552
+ }
549
553
}
550
554
551
555
fn type_size_of < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
@@ -639,7 +643,7 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
639
643
assert ! ( self . places[ local] . is_none( ) ) ;
640
644
self . places [ local] = Some ( value) ;
641
645
642
- if self . tcx . sess . opts . debugging_opts . mir_opt_level >= 2 {
646
+ if self . should_const_prop ( ) {
643
647
self . replace_with_const ( rval, value, statement. source_info . span ) ;
644
648
}
645
649
}
@@ -656,75 +660,112 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
656
660
location : Location ,
657
661
) {
658
662
self . super_terminator ( terminator, location) ;
659
- let source_info = terminator. source_info ; ;
660
- if let TerminatorKind :: Assert { expected, msg, cond, .. } = & terminator. kind {
661
- if let Some ( value) = self . eval_operand ( & cond, source_info) {
662
- trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
663
- let expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ;
664
- if expected != self . ecx . read_scalar ( value) . unwrap ( ) {
665
- // poison all places this operand references so that further code
666
- // doesn't use the invalid value
667
- match cond {
668
- Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
669
- let mut place = place;
670
- while let Place :: Projection ( ref proj) = * place {
671
- place = & proj. base ;
672
- }
673
- if let Place :: Base ( PlaceBase :: Local ( local) ) = * place {
674
- self . places [ local] = None ;
663
+ let source_info = terminator. source_info ;
664
+ match & mut terminator. kind {
665
+ TerminatorKind :: Assert { expected, msg, ref mut cond, .. } => {
666
+ if let Some ( value) = self . eval_operand ( & cond, source_info) {
667
+ trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
668
+ let expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ;
669
+ let value_const = self . ecx . read_scalar ( value) . unwrap ( ) ;
670
+ if expected != value_const {
671
+ // poison all places this operand references so that further code
672
+ // doesn't use the invalid value
673
+ match cond {
674
+ Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
675
+ let mut place = place;
676
+ while let Place :: Projection ( ref proj) = * place {
677
+ place = & proj. base ;
678
+ }
679
+ if let Place :: Base ( PlaceBase :: Local ( local) ) = * place {
680
+ self . places [ local] = None ;
681
+ }
682
+ } ,
683
+ Operand :: Constant ( _) => { }
684
+ }
685
+ let span = terminator. source_info . span ;
686
+ let hir_id = self
687
+ . tcx
688
+ . hir ( )
689
+ . as_local_hir_id ( self . source . def_id ( ) )
690
+ . expect ( "some part of a failing const eval must be local" ) ;
691
+ use rustc:: mir:: interpret:: InterpError :: * ;
692
+ let msg = match msg {
693
+ Overflow ( _) |
694
+ OverflowNeg |
695
+ DivisionByZero |
696
+ RemainderByZero => msg. description ( ) . to_owned ( ) ,
697
+ BoundsCheck { ref len, ref index } => {
698
+ let len = self
699
+ . eval_operand ( len, source_info)
700
+ . expect ( "len must be const" ) ;
701
+ let len = match self . ecx . read_scalar ( len) {
702
+ Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
703
+ bits, ..
704
+ } ) ) => bits,
705
+ other => bug ! ( "const len not primitive: {:?}" , other) ,
706
+ } ;
707
+ let index = self
708
+ . eval_operand ( index, source_info)
709
+ . expect ( "index must be const" ) ;
710
+ let index = match self . ecx . read_scalar ( index) {
711
+ Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
712
+ bits, ..
713
+ } ) ) => bits,
714
+ other => bug ! ( "const index not primitive: {:?}" , other) ,
715
+ } ;
716
+ format ! (
717
+ "index out of bounds: \
718
+ the len is {} but the index is {}",
719
+ len,
720
+ index,
721
+ )
722
+ } ,
723
+ // Need proper const propagator for these
724
+ _ => return ,
725
+ } ;
726
+ self . tcx . lint_hir (
727
+ :: rustc:: lint:: builtin:: CONST_ERR ,
728
+ hir_id,
729
+ span,
730
+ & msg,
731
+ ) ;
732
+ } else {
733
+ if self . should_const_prop ( ) {
734
+ if let ScalarMaybeUndef :: Scalar ( scalar) = value_const {
735
+ * cond = self . operand_from_scalar (
736
+ scalar,
737
+ self . tcx . types . bool ,
738
+ source_info. span ,
739
+ ) ;
675
740
}
676
- } ,
677
- Operand :: Constant ( _) => { }
741
+ }
678
742
}
679
- let span = terminator. source_info . span ;
680
- let hir_id = self
681
- . tcx
682
- . hir ( )
683
- . as_local_hir_id ( self . source . def_id ( ) )
684
- . expect ( "some part of a failing const eval must be local" ) ;
685
- use rustc:: mir:: interpret:: InterpError :: * ;
686
- let msg = match msg {
687
- Overflow ( _) |
688
- OverflowNeg |
689
- DivisionByZero |
690
- RemainderByZero => msg. description ( ) . to_owned ( ) ,
691
- BoundsCheck { ref len, ref index } => {
692
- let len = self
693
- . eval_operand ( len, source_info)
694
- . expect ( "len must be const" ) ;
695
- let len = match self . ecx . read_scalar ( len) {
696
- Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
697
- bits, ..
698
- } ) ) => bits,
699
- other => bug ! ( "const len not primitive: {:?}" , other) ,
700
- } ;
701
- let index = self
702
- . eval_operand ( index, source_info)
703
- . expect ( "index must be const" ) ;
704
- let index = match self . ecx . read_scalar ( index) {
705
- Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
706
- bits, ..
707
- } ) ) => bits,
708
- other => bug ! ( "const index not primitive: {:?}" , other) ,
709
- } ;
710
- format ! (
711
- "index out of bounds: \
712
- the len is {} but the index is {}",
713
- len,
714
- index,
715
- )
716
- } ,
717
- // Need proper const propagator for these
718
- _ => return ,
719
- } ;
720
- self . tcx . lint_hir (
721
- :: rustc:: lint:: builtin:: CONST_ERR ,
722
- hir_id,
723
- span,
724
- & msg,
725
- ) ;
726
743
}
727
- }
744
+ } ,
745
+ TerminatorKind :: SwitchInt { ref mut discr, switch_ty, .. } => {
746
+ if self . should_const_prop ( ) {
747
+ if let Some ( value) = self . eval_operand ( & discr, source_info) {
748
+ if let ScalarMaybeUndef :: Scalar ( scalar) =
749
+ self . ecx . read_scalar ( value) . unwrap ( ) {
750
+ * discr = self . operand_from_scalar ( scalar, switch_ty, source_info. span ) ;
751
+ }
752
+ }
753
+ }
754
+ } ,
755
+ //none of these have Operands to const-propagate
756
+ TerminatorKind :: Goto { .. } |
757
+ TerminatorKind :: Resume |
758
+ TerminatorKind :: Abort |
759
+ TerminatorKind :: Return |
760
+ TerminatorKind :: Unreachable |
761
+ TerminatorKind :: Drop { .. } |
762
+ TerminatorKind :: DropAndReplace { .. } |
763
+ TerminatorKind :: Yield { .. } |
764
+ TerminatorKind :: GeneratorDrop |
765
+ TerminatorKind :: FalseEdges { .. } |
766
+ TerminatorKind :: FalseUnwind { .. } => { }
767
+ //FIXME(wesleywiser) Call does have Operands that could be const-propagated
768
+ TerminatorKind :: Call { .. } => { }
728
769
}
729
770
}
730
771
}
0 commit comments