@@ -546,6 +546,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
546546 }
547547 }
548548 }
549+
550+ fn should_const_prop ( & self ) -> bool {
551+ self . tcx . sess . opts . debugging_opts . mir_opt_level >= 2
552+ }
549553}
550554
551555fn 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> {
639643 assert ! ( self . places[ local] . is_none( ) ) ;
640644 self . places [ local] = Some ( value) ;
641645
642- if self . tcx . sess . opts . debugging_opts . mir_opt_level >= 2 {
646+ if self . should_const_prop ( ) {
643647 self . replace_with_const ( rval, value, statement. source_info . span ) ;
644648 }
645649 }
@@ -656,75 +660,112 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
656660 location : Location ,
657661 ) {
658662 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+ ) ;
675740 }
676- } ,
677- Operand :: Constant ( _) => { }
741+ }
678742 }
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- ) ;
726743 }
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 { .. } => { }
728769 }
729770 }
730771}
0 commit comments