@@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
118118struct ConstPropMachine ;
119119
120120impl < ' mir , ' tcx > interpret:: Machine < ' mir , ' tcx > for ConstPropMachine {
121- type MemoryKinds = !;
121+ type MemoryKinds = !;
122122 type PointerTag = ( ) ;
123123 type ExtraFnVal = !;
124124
@@ -460,79 +460,80 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
460460 let span = source_info. span ;
461461
462462 // perform any special checking for specific Rvalue types
463- if let Rvalue :: UnaryOp ( op, arg) = rvalue {
464- trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
465- let overflow_check = self . tcx . sess . overflow_checks ( ) ;
466-
467- self . use_ecx ( source_info, |this| {
468- // We check overflow in debug mode already
469- // so should only check in release mode.
470- if * op == UnOp :: Neg && !overflow_check {
471- let ty = arg. ty ( & this. local_decls , this. tcx ) ;
472-
473- if ty. is_integral ( ) {
474- let arg = this. ecx . eval_operand ( arg, None ) ?;
475- let prim = this. ecx . read_immediate ( arg) ?;
476- // Need to do overflow check here: For actual CTFE, MIR
477- // generation emits code that does this before calling the op.
478- if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
479- throw_panic ! ( OverflowNeg )
463+ match rvalue {
464+ Rvalue :: UnaryOp ( UnOp :: Neg , arg) => {
465+ trace ! ( "checking UnaryOp(op = Neg, arg = {:?})" , arg) ;
466+ let overflow_check = self . tcx . sess . overflow_checks ( ) ;
467+
468+ self . use_ecx ( source_info, |this| {
469+ // We check overflow in debug mode already
470+ // so should only check in release mode.
471+ if !overflow_check {
472+ let ty = arg. ty ( & this. local_decls , this. tcx ) ;
473+
474+ if ty. is_integral ( ) {
475+ let arg = this. ecx . eval_operand ( arg, None ) ?;
476+ let prim = this. ecx . read_immediate ( arg) ?;
477+ // Need to do overflow check here: For actual CTFE, MIR
478+ // generation emits code that does this before calling the op.
479+ if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
480+ throw_panic ! ( OverflowNeg )
481+ }
480482 }
481483 }
482- }
483484
484- Ok ( ( ) )
485- } ) ?;
486- } else if let Rvalue :: BinaryOp ( op, left, right) = rvalue {
487- trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
488-
489- let r = self . use_ecx ( source_info, |this| {
490- this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
491- } ) ?;
492- if * op == BinOp :: Shr || * op == BinOp :: Shl {
493- let left_bits = place_layout. size . bits ( ) ;
494- let right_size = r. layout . size ;
495- let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
496- if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
497- let source_scope_local_data = match self . source_scope_local_data {
498- ClearCrossCrate :: Set ( ref data) => data,
499- ClearCrossCrate :: Clear => return None ,
500- } ;
501- let dir = if * op == BinOp :: Shr {
502- "right"
503- } else {
504- "left"
505- } ;
506- let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
507- self . tcx . lint_hir (
508- :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
509- hir_id,
510- span,
511- & format ! ( "attempt to shift {} with overflow" , dir) ) ;
512- return None ;
513- }
485+ Ok ( ( ) )
486+ } ) ?;
514487 }
515- self . use_ecx ( source_info, |this| {
516- let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
517- let ( _, overflow, _ty) = this. ecx . overflowing_binary_op ( * op, l, r) ?;
518-
519- // We check overflow in debug mode already
520- // so should only check in release mode.
521- if !this. tcx . sess . overflow_checks ( ) && overflow {
522- let err = err_panic ! ( Overflow ( * op) ) . into ( ) ;
523- return Err ( err) ;
488+
489+ Rvalue :: BinaryOp ( op, left, right) => {
490+ trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
491+
492+ let r = self . use_ecx ( source_info, |this| {
493+ this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
494+ } ) ?;
495+ if * op == BinOp :: Shr || * op == BinOp :: Shl {
496+ let left_bits = place_layout. size . bits ( ) ;
497+ let right_size = r. layout . size ;
498+ let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
499+ if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
500+ let source_scope_local_data = match self . source_scope_local_data {
501+ ClearCrossCrate :: Set ( ref data) => data,
502+ ClearCrossCrate :: Clear => return None ,
503+ } ;
504+ let dir = if * op == BinOp :: Shr {
505+ "right"
506+ } else {
507+ "left"
508+ } ;
509+ let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
510+ self . tcx . lint_hir (
511+ :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
512+ hir_id,
513+ span,
514+ & format ! ( "attempt to shift {} with overflow" , dir) ) ;
515+ return None ;
516+ }
524517 }
518+ self . use_ecx ( source_info, |this| {
519+ let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
520+ let ( _, overflow, _ty) = this. ecx . overflowing_binary_op ( * op, l, r) ?;
521+
522+ // We check overflow in debug mode already
523+ // so should only check in release mode.
524+ if !this. tcx . sess . overflow_checks ( ) && overflow {
525+ let err = err_panic ! ( Overflow ( * op) ) . into ( ) ;
526+ return Err ( err) ;
527+ }
525528
526- Ok ( ( ) )
527- } ) ?;
528- } else if let Rvalue :: Ref ( _, _, place) = rvalue {
529- trace ! ( "checking Ref({:?})" , place) ;
530- // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
531- // from a function argument that hasn't been assigned to in this function.
532- if let Place {
533- base : PlaceBase :: Local ( local) ,
534- projection : box [ ]
535- } = place {
529+ Ok ( ( ) )
530+ } ) ?;
531+ }
532+
533+ Rvalue :: Ref ( _, _, Place { base : PlaceBase :: Local ( local) , projection : box [ ] } ) => {
534+ trace ! ( "checking Ref({:?})" , place) ;
535+ // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
536+ // from a function argument that hasn't been assigned to in this function.
536537 let alive =
537538 if let LocalValue :: Live ( _) = self . ecx . frame ( ) . locals [ * local] . value {
538539 true
@@ -543,12 +544,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
543544 return None ;
544545 }
545546 }
546- } else if let Rvalue :: Aggregate ( _ , operands ) = rvalue {
547- // FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
548- // `SimplifyLocals` doesn't know it can remove.
549- if operands . len ( ) == 0 {
547+
548+ Rvalue :: Aggregate ( _ , operands ) if operands . len ( ) == 0 => {
549+ // FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
550+ // `SimplifyLocals` doesn't know it can remove.
550551 return None ;
551552 }
553+
554+ _ => { }
552555 }
553556
554557 self . use_ecx ( source_info, |this| {
0 commit comments