@@ -480,6 +480,76 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
480
480
Some ( ( ) )
481
481
}
482
482
483
+ fn check_assertion (
484
+ & mut self ,
485
+ expected : bool ,
486
+ msg : & AssertKind < Operand < ' tcx > > ,
487
+ cond : & Operand < ' tcx > ,
488
+ location : Location ,
489
+ ) -> Option < !> {
490
+ let ref value = self . eval_operand ( & cond, location) ?;
491
+ trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
492
+
493
+ let expected = Scalar :: from_bool ( expected) ;
494
+ let value_const = self . use_ecx ( location, |this| this. ecx . read_scalar ( & value) ) ?;
495
+
496
+ if expected != value_const {
497
+ // Poison all places this operand references so that further code
498
+ // doesn't use the invalid value
499
+ match cond {
500
+ Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
501
+ Self :: remove_const ( & mut self . ecx , place. local ) ;
502
+ }
503
+ Operand :: Constant ( _) => { }
504
+ }
505
+ enum DbgVal < T > {
506
+ Val ( T ) ,
507
+ Underscore ,
508
+ }
509
+ impl < T : std:: fmt:: Debug > std:: fmt:: Debug for DbgVal < T > {
510
+ fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
511
+ match self {
512
+ Self :: Val ( val) => val. fmt ( fmt) ,
513
+ Self :: Underscore => fmt. write_str ( "_" ) ,
514
+ }
515
+ }
516
+ }
517
+ let mut eval_to_int = |op| {
518
+ // This can be `None` if the lhs wasn't const propagated and we just
519
+ // triggered the assert on the value of the rhs.
520
+ self . eval_operand ( op, location)
521
+ . and_then ( |op| self . ecx . read_immediate ( & op) . ok ( ) )
522
+ . map_or ( DbgVal :: Underscore , |op| DbgVal :: Val ( op. to_const_int ( ) ) )
523
+ } ;
524
+ let msg = match msg {
525
+ AssertKind :: DivisionByZero ( op) => AssertKind :: DivisionByZero ( eval_to_int ( op) ) ,
526
+ AssertKind :: RemainderByZero ( op) => AssertKind :: RemainderByZero ( eval_to_int ( op) ) ,
527
+ AssertKind :: Overflow ( bin_op @ ( BinOp :: Div | BinOp :: Rem ) , op1, op2) => {
528
+ // Division overflow is *UB* in the MIR, and different than the
529
+ // other overflow checks.
530
+ AssertKind :: Overflow ( * bin_op, eval_to_int ( op1) , eval_to_int ( op2) )
531
+ }
532
+ AssertKind :: BoundsCheck { ref len, ref index } => {
533
+ let len = eval_to_int ( len) ;
534
+ let index = eval_to_int ( index) ;
535
+ AssertKind :: BoundsCheck { len, index }
536
+ }
537
+ // Remaining overflow errors are already covered by checks on the binary operators.
538
+ AssertKind :: Overflow ( ..) | AssertKind :: OverflowNeg ( _) => return None ,
539
+ // Need proper const propagator for these.
540
+ _ => return None ,
541
+ } ;
542
+ self . report_assert_as_lint (
543
+ lint:: builtin:: UNCONDITIONAL_PANIC ,
544
+ location,
545
+ "this operation will panic at runtime" ,
546
+ msg,
547
+ ) ;
548
+ }
549
+
550
+ None
551
+ }
552
+
483
553
fn ensure_not_propagated ( & self , local : Local ) {
484
554
if cfg ! ( debug_assertions) {
485
555
assert ! (
@@ -585,78 +655,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
585
655
self . super_terminator ( terminator, location) ;
586
656
match & terminator. kind {
587
657
TerminatorKind :: Assert { expected, ref msg, ref cond, .. } => {
588
- if let Some ( ref value) = self . eval_operand ( & cond, location) {
589
- trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
590
- let expected = Scalar :: from_bool ( * expected) ;
591
- let Ok ( value_const) = self . ecx . read_scalar ( & value) else {
592
- // FIXME should be used use_ecx rather than a local match... but we have
593
- // quite a few of these read_scalar/read_immediate that need fixing.
594
- return
595
- } ;
596
- if expected != value_const {
597
- enum DbgVal < T > {
598
- Val ( T ) ,
599
- Underscore ,
600
- }
601
- impl < T : std:: fmt:: Debug > std:: fmt:: Debug for DbgVal < T > {
602
- fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
603
- match self {
604
- Self :: Val ( val) => val. fmt ( fmt) ,
605
- Self :: Underscore => fmt. write_str ( "_" ) ,
606
- }
607
- }
608
- }
609
- let mut eval_to_int = |op| {
610
- // This can be `None` if the lhs wasn't const propagated and we just
611
- // triggered the assert on the value of the rhs.
612
- self . eval_operand ( op, location)
613
- . and_then ( |op| self . ecx . read_immediate ( & op) . ok ( ) )
614
- . map_or ( DbgVal :: Underscore , |op| DbgVal :: Val ( op. to_const_int ( ) ) )
615
- } ;
616
- let msg = match msg {
617
- AssertKind :: DivisionByZero ( op) => {
618
- Some ( AssertKind :: DivisionByZero ( eval_to_int ( op) ) )
619
- }
620
- AssertKind :: RemainderByZero ( op) => {
621
- Some ( AssertKind :: RemainderByZero ( eval_to_int ( op) ) )
622
- }
623
- AssertKind :: Overflow ( bin_op @ ( BinOp :: Div | BinOp :: Rem ) , op1, op2) => {
624
- // Division overflow is *UB* in the MIR, and different than the
625
- // other overflow checks.
626
- Some ( AssertKind :: Overflow (
627
- * bin_op,
628
- eval_to_int ( op1) ,
629
- eval_to_int ( op2) ,
630
- ) )
631
- }
632
- AssertKind :: BoundsCheck { ref len, ref index } => {
633
- let len = eval_to_int ( len) ;
634
- let index = eval_to_int ( index) ;
635
- Some ( AssertKind :: BoundsCheck { len, index } )
636
- }
637
- // Remaining overflow errors are already covered by checks on the binary operators.
638
- AssertKind :: Overflow ( ..) | AssertKind :: OverflowNeg ( _) => None ,
639
- // Need proper const propagator for these.
640
- _ => None ,
641
- } ;
642
- // Poison all places this operand references so that further code
643
- // doesn't use the invalid value
644
- match cond {
645
- Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
646
- Self :: remove_const ( & mut self . ecx , place. local ) ;
647
- }
648
- Operand :: Constant ( _) => { }
649
- }
650
- if let Some ( msg) = msg {
651
- self . report_assert_as_lint (
652
- lint:: builtin:: UNCONDITIONAL_PANIC ,
653
- location,
654
- "this operation will panic at runtime" ,
655
- msg,
656
- ) ;
657
- }
658
- }
659
- }
658
+ self . check_assertion ( * expected, msg, cond, location) ;
660
659
}
661
660
// None of these have Operands to const-propagate.
662
661
TerminatorKind :: Goto { .. }
0 commit comments