44use std:: borrow:: Cow ;
55use std:: cell:: Cell ;
66
7- use rustc:: mir:: interpret:: { InterpError , InterpResult , Scalar } ;
7+ use rustc:: lint;
8+ use rustc:: mir:: interpret:: { InterpResult , Scalar } ;
89use rustc:: mir:: visit:: {
910 MutVisitor , MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor ,
1011} ;
@@ -292,7 +293,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
292293struct ConstPropagator < ' mir , ' tcx > {
293294 ecx : InterpCx < ' mir , ' tcx , ConstPropMachine > ,
294295 tcx : TyCtxt < ' tcx > ,
295- source : MirSource < ' tcx > ,
296296 can_const_prop : IndexVec < Local , ConstPropMode > ,
297297 param_env : ParamEnv < ' tcx > ,
298298 // FIXME(eddyb) avoid cloning these two fields more than once,
@@ -372,7 +372,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
372372 ConstPropagator {
373373 ecx,
374374 tcx,
375- source,
376375 param_env,
377376 can_const_prop,
378377 // FIXME(eddyb) avoid cloning these two fields more than once,
@@ -501,19 +500,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
501500 }
502501 }
503502
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 : & str ,
508+ panic : AssertKind < u64 > ,
509+ ) -> Option < ( ) > {
506510 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 ;
517517 }
518518
519519 fn check_unary_op (
@@ -530,7 +530,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
530530 // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
531531 // appropriate to use.
532532 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:: OVERFLOW ,
535+ source_info,
536+ "this arithmetic operation will overflow" ,
537+ AssertKind :: OverflowNeg ,
538+ ) ?;
534539 }
535540
536541 Some ( ( ) )
@@ -552,17 +557,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
552557 let right_size = r. layout . size ;
553558 let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
554559 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 ;
560+ self . report_assert_as_lint (
561+ lint:: builtin:: EXCEEDING_BITSHIFTS ,
562+ source_info,
563+ "this arithmetic operation will overflow" ,
564+ AssertKind :: Overflow ( op) ,
565+ ) ?;
566566 }
567567 }
568568
@@ -572,7 +572,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
572572 let ( _res, overflow, _ty) = this. ecx . overflowing_binary_op ( op, l, r) ?;
573573 Ok ( overflow)
574574 } ) ? {
575- self . report_panic_as_lint ( source_info, AssertKind :: Overflow ( op) ) ?;
575+ self . report_assert_as_lint (
576+ lint:: builtin:: OVERFLOW ,
577+ source_info,
578+ "this arithmetic operation will overflow" ,
579+ AssertKind :: Overflow ( op) ,
580+ ) ?;
576581 }
577582
578583 Some ( ( ) )
@@ -595,8 +600,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
595600 return None ;
596601 }
597602
598- let overflow_check = self . tcx . sess . overflow_checks ( ) ;
599-
600603 // Perform any special handling for specific Rvalue types.
601604 // Generally, checks here fall into one of two categories:
602605 // 1. Additional checking to provide useful lints to the user
@@ -606,21 +609,26 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
606609 // - In this case, we'll return `None` from this function to stop evaluation.
607610 match rvalue {
608611 // 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 => {
612+ // We do this here and not in the `Assert` terminator as that terminator is
613+ // only sometimes emitted (overflow checks can be disabled), but we want to always
614+ // lint.
615+ Rvalue :: UnaryOp ( op, arg) => {
612616 trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
613617 self . check_unary_op ( * op, arg, source_info) ?;
614618 }
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 => {
619+ Rvalue :: BinaryOp ( op, left, right) => {
621620 trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
622621 self . check_binary_op ( * op, left, right, source_info, place_layout) ?;
623622 }
623+ Rvalue :: CheckedBinaryOp ( op, left, right) => {
624+ trace ! (
625+ "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})" ,
626+ op,
627+ left,
628+ right
629+ ) ;
630+ self . check_binary_op ( * op, left, right, source_info, place_layout) ?;
631+ }
624632
625633 // Do not try creating references (#67862)
626634 Rvalue :: Ref ( _, _, place_ref) => {
@@ -898,54 +906,39 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
898906 }
899907 Operand :: Constant ( _) => { }
900908 }
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- } ,
909+ let msg = match msg {
910+ AssertKind :: DivisionByZero => AssertKind :: DivisionByZero ,
911+ AssertKind :: RemainderByZero => AssertKind :: RemainderByZero ,
912+ AssertKind :: BoundsCheck { ref len, ref index } => {
913+ let len =
914+ self . eval_operand ( len, source_info) . expect ( "len must be const" ) ;
915+ let len = self
916+ . ecx
917+ . read_scalar ( len)
918+ . unwrap ( )
919+ . to_machine_usize ( & self . tcx )
920+ . unwrap ( ) ;
921+ let index = self
922+ . eval_operand ( index, source_info)
923+ . expect ( "index must be const" ) ;
924+ let index = self
925+ . ecx
926+ . read_scalar ( index)
927+ . unwrap ( )
928+ . to_machine_usize ( & self . tcx )
929+ . unwrap ( ) ;
930+ AssertKind :: BoundsCheck { len, index }
931+ }
932+ // Overflow is are already covered by checks on the binary operators.
933+ AssertKind :: Overflow ( _) | AssertKind :: OverflowNeg => return ,
934+ // Need proper const propagator for these.
935+ _ => return ,
936+ } ;
937+ self . report_assert_as_lint (
938+ lint:: builtin:: PANIC ,
939+ source_info,
940+ "this operation will panic at runtime" ,
941+ msg,
949942 ) ;
950943 } else {
951944 if self . should_const_prop ( value) {
0 commit comments