4
4
use std:: borrow:: Cow ;
5
5
use std:: cell:: Cell ;
6
6
7
- use rustc:: mir:: interpret:: { InterpError , InterpResult , Scalar } ;
7
+ use rustc:: lint;
8
+ use rustc:: mir:: interpret:: { InterpResult , Scalar } ;
8
9
use rustc:: mir:: visit:: {
9
10
MutVisitor , MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor ,
10
11
} ;
@@ -292,7 +293,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
292
293
struct ConstPropagator < ' mir , ' tcx > {
293
294
ecx : InterpCx < ' mir , ' tcx , ConstPropMachine > ,
294
295
tcx : TyCtxt < ' tcx > ,
295
- source : MirSource < ' tcx > ,
296
296
can_const_prop : IndexVec < Local , ConstPropMode > ,
297
297
param_env : ParamEnv < ' tcx > ,
298
298
// FIXME(eddyb) avoid cloning these two fields more than once,
@@ -372,7 +372,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
372
372
ConstPropagator {
373
373
ecx,
374
374
tcx,
375
- source,
376
375
param_env,
377
376
can_const_prop,
378
377
// FIXME(eddyb) avoid cloning these two fields more than once,
@@ -501,19 +500,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
501
500
}
502
501
}
503
502
504
- fn report_panic_as_lint ( & self , source_info : SourceInfo , panic : AssertKind < u64 > ) -> Option < ( ) > {
505
- // Somewhat convoluted way to re-use the CTFE error reporting code.
503
+ fn report_assert_as_lint (
504
+ & self ,
505
+ lint : & ' static lint:: Lint ,
506
+ source_info : SourceInfo ,
507
+ message : & ' static str ,
508
+ panic : AssertKind < u64 > ,
509
+ ) -> Option < ( ) > {
506
510
let lint_root = self . lint_root ( source_info) ?;
507
- let error = InterpError :: MachineStop ( Box :: new ( format ! ( "{:?}" , panic) ) ) ;
508
- let mut diagnostic = error_to_const_error ( & self . ecx , error. into ( ) ) ;
509
- diagnostic. span = source_info. span ; // fix the span
510
- diagnostic. report_as_lint (
511
- self . tcx . at ( source_info. span ) ,
512
- "this expression will panic at runtime" ,
513
- lint_root,
514
- None ,
515
- ) ;
516
- None
511
+ self . tcx . struct_span_lint_hir ( lint, lint_root, source_info. span , |lint| {
512
+ let mut err = lint. build ( message) ;
513
+ err. span_label ( source_info. span , format ! ( "{:?}" , panic) ) ;
514
+ err. emit ( )
515
+ } ) ;
516
+ return None ;
517
517
}
518
518
519
519
fn check_unary_op (
@@ -530,7 +530,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
530
530
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
531
531
// appropriate to use.
532
532
assert_eq ! ( op, UnOp :: Neg , "Neg is the only UnOp that can overflow" ) ;
533
- self . report_panic_as_lint ( source_info, AssertKind :: OverflowNeg ) ?;
533
+ self . report_assert_as_lint (
534
+ lint:: builtin:: ARITHMETIC_OVERFLOW ,
535
+ source_info,
536
+ "this arithmetic operation will overflow" ,
537
+ AssertKind :: OverflowNeg ,
538
+ ) ?;
534
539
}
535
540
536
541
Some ( ( ) )
@@ -542,27 +547,24 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
542
547
left : & Operand < ' tcx > ,
543
548
right : & Operand < ' tcx > ,
544
549
source_info : SourceInfo ,
545
- place_layout : TyLayout < ' tcx > ,
546
550
) -> Option < ( ) > {
547
551
let r =
548
552
self . use_ecx ( |this| this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?) ) ?;
549
553
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
550
554
if op == BinOp :: Shr || op == BinOp :: Shl {
551
- let left_bits = place_layout. size . bits ( ) ;
555
+ // We need the type of the LHS. We cannot use `place_layout` as that is the type
556
+ // of the result, which for checked binops is not the same!
557
+ let left_ty = left. ty ( & self . local_decls , self . tcx ) ;
558
+ let left_size_bits = self . ecx . layout_of ( left_ty) . ok ( ) ?. size . bits ( ) ;
552
559
let right_size = r. layout . size ;
553
560
let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
554
- if r_bits. map_or ( false , |b| b >= left_bits as u128 ) {
555
- let lint_root = self . lint_root ( source_info) ?;
556
- self . tcx . struct_span_lint_hir (
557
- :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
558
- lint_root,
559
- source_info. span ,
560
- |lint| {
561
- let dir = if op == BinOp :: Shr { "right" } else { "left" } ;
562
- lint. build ( & format ! ( "attempt to shift {} with overflow" , dir) ) . emit ( )
563
- } ,
564
- ) ;
565
- return None ;
561
+ if r_bits. map_or ( false , |b| b >= left_size_bits as u128 ) {
562
+ self . report_assert_as_lint (
563
+ lint:: builtin:: ARITHMETIC_OVERFLOW ,
564
+ source_info,
565
+ "this arithmetic operation will overflow" ,
566
+ AssertKind :: Overflow ( op) ,
567
+ ) ?;
566
568
}
567
569
}
568
570
@@ -572,7 +574,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
572
574
let ( _res, overflow, _ty) = this. ecx . overflowing_binary_op ( op, l, r) ?;
573
575
Ok ( overflow)
574
576
} ) ? {
575
- self . report_panic_as_lint ( source_info, AssertKind :: Overflow ( op) ) ?;
577
+ self . report_assert_as_lint (
578
+ lint:: builtin:: ARITHMETIC_OVERFLOW ,
579
+ source_info,
580
+ "this arithmetic operation will overflow" ,
581
+ AssertKind :: Overflow ( op) ,
582
+ ) ?;
576
583
}
577
584
578
585
Some ( ( ) )
@@ -595,8 +602,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
595
602
return None ;
596
603
}
597
604
598
- let overflow_check = self . tcx . sess . overflow_checks ( ) ;
599
-
600
605
// Perform any special handling for specific Rvalue types.
601
606
// Generally, checks here fall into one of two categories:
602
607
// 1. Additional checking to provide useful lints to the user
@@ -606,20 +611,25 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
606
611
// - In this case, we'll return `None` from this function to stop evaluation.
607
612
match rvalue {
608
613
// Additional checking: give lints to the user if an overflow would occur.
609
- // If `overflow_check` is set, running const-prop on the `Assert` terminators
610
- // will already generate the appropriate messages.
611
- Rvalue :: UnaryOp ( op, arg) if !overflow_check => {
614
+ // We do this here and not in the `Assert` terminator as that terminator is
615
+ // only sometimes emitted (overflow checks can be disabled), but we want to always
616
+ // lint.
617
+ Rvalue :: UnaryOp ( op, arg) => {
612
618
trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
613
619
self . check_unary_op ( * op, arg, source_info) ?;
614
620
}
615
-
616
- // Additional checking: check for overflows on integer binary operations and report
617
- // them to the user as lints.
618
- // If `overflow_check` is set, running const-prop on the `Assert` terminators
619
- // will already generate the appropriate messages.
620
- Rvalue :: BinaryOp ( op, left, right) if !overflow_check => {
621
+ Rvalue :: BinaryOp ( op, left, right) => {
621
622
trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
622
- self . check_binary_op ( * op, left, right, source_info, place_layout) ?;
623
+ self . check_binary_op ( * op, left, right, source_info) ?;
624
+ }
625
+ Rvalue :: CheckedBinaryOp ( op, left, right) => {
626
+ trace ! (
627
+ "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})" ,
628
+ op,
629
+ left,
630
+ right
631
+ ) ;
632
+ self . check_binary_op ( * op, left, right, source_info) ?;
623
633
}
624
634
625
635
// Do not try creating references (#67862)
@@ -898,54 +908,39 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
898
908
}
899
909
Operand :: Constant ( _) => { }
900
910
}
901
- let span = terminator. source_info . span ;
902
- let hir_id = self
903
- . tcx
904
- . hir ( )
905
- . as_local_hir_id ( self . source . def_id ( ) )
906
- . expect ( "some part of a failing const eval must be local" ) ;
907
- self . tcx . struct_span_lint_hir (
908
- :: rustc:: lint:: builtin:: CONST_ERR ,
909
- hir_id,
910
- span,
911
- |lint| {
912
- let msg = match msg {
913
- AssertKind :: Overflow ( _)
914
- | AssertKind :: OverflowNeg
915
- | AssertKind :: DivisionByZero
916
- | AssertKind :: RemainderByZero => msg. description ( ) . to_owned ( ) ,
917
- AssertKind :: BoundsCheck { ref len, ref index } => {
918
- let len = self
919
- . eval_operand ( len, source_info)
920
- . expect ( "len must be const" ) ;
921
- let len = match self . ecx . read_scalar ( len) {
922
- Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Raw {
923
- data,
924
- ..
925
- } ) ) => data,
926
- other => bug ! ( "const len not primitive: {:?}" , other) ,
927
- } ;
928
- let index = self
929
- . eval_operand ( index, source_info)
930
- . expect ( "index must be const" ) ;
931
- let index = match self . ecx . read_scalar ( index) {
932
- Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Raw {
933
- data,
934
- ..
935
- } ) ) => data,
936
- other => bug ! ( "const index not primitive: {:?}" , other) ,
937
- } ;
938
- format ! (
939
- "index out of bounds: \
940
- the len is {} but the index is {}",
941
- len, index,
942
- )
943
- }
944
- // Need proper const propagator for these
945
- _ => return ,
946
- } ;
947
- lint. build ( & msg) . emit ( )
948
- } ,
911
+ let msg = match msg {
912
+ AssertKind :: DivisionByZero => AssertKind :: DivisionByZero ,
913
+ AssertKind :: RemainderByZero => AssertKind :: RemainderByZero ,
914
+ AssertKind :: BoundsCheck { ref len, ref index } => {
915
+ let len =
916
+ self . eval_operand ( len, source_info) . expect ( "len must be const" ) ;
917
+ let len = self
918
+ . ecx
919
+ . read_scalar ( len)
920
+ . unwrap ( )
921
+ . to_machine_usize ( & self . tcx )
922
+ . unwrap ( ) ;
923
+ let index = self
924
+ . eval_operand ( index, source_info)
925
+ . expect ( "index must be const" ) ;
926
+ let index = self
927
+ . ecx
928
+ . read_scalar ( index)
929
+ . unwrap ( )
930
+ . to_machine_usize ( & self . tcx )
931
+ . unwrap ( ) ;
932
+ AssertKind :: BoundsCheck { len, index }
933
+ }
934
+ // Overflow is are already covered by checks on the binary operators.
935
+ AssertKind :: Overflow ( _) | AssertKind :: OverflowNeg => return ,
936
+ // Need proper const propagator for these.
937
+ _ => return ,
938
+ } ;
939
+ self . report_assert_as_lint (
940
+ lint:: builtin:: UNCONDITIONAL_PANIC ,
941
+ source_info,
942
+ "this operation will panic at runtime" ,
943
+ msg,
949
944
) ;
950
945
} else {
951
946
if self . should_const_prop ( value) {
0 commit comments