@@ -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
@@ -435,79 +435,80 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
435435 let span = source_info. span ;
436436
437437 // perform any special checking for specific Rvalue types
438- if let Rvalue :: UnaryOp ( op, arg) = rvalue {
439- trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
440- let overflow_check = self . tcx . sess . overflow_checks ( ) ;
441-
442- self . use_ecx ( source_info, |this| {
443- // We check overflow in debug mode already
444- // so should only check in release mode.
445- if * op == UnOp :: Neg && !overflow_check {
446- let ty = arg. ty ( & this. local_decls , this. tcx ) ;
447-
448- if ty. is_integral ( ) {
449- let arg = this. ecx . eval_operand ( arg, None ) ?;
450- let prim = this. ecx . read_immediate ( arg) ?;
451- // Need to do overflow check here: For actual CTFE, MIR
452- // generation emits code that does this before calling the op.
453- if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
454- throw_panic ! ( OverflowNeg )
438+ match rvalue {
439+ Rvalue :: UnaryOp ( UnOp :: Neg , arg) => {
440+ trace ! ( "checking UnaryOp(op = Neg, arg = {:?})" , arg) ;
441+ let overflow_check = self . tcx . sess . overflow_checks ( ) ;
442+
443+ self . use_ecx ( source_info, |this| {
444+ // We check overflow in debug mode already
445+ // so should only check in release mode.
446+ if !overflow_check {
447+ let ty = arg. ty ( & this. local_decls , this. tcx ) ;
448+
449+ if ty. is_integral ( ) {
450+ let arg = this. ecx . eval_operand ( arg, None ) ?;
451+ let prim = this. ecx . read_immediate ( arg) ?;
452+ // Need to do overflow check here: For actual CTFE, MIR
453+ // generation emits code that does this before calling the op.
454+ if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
455+ throw_panic ! ( OverflowNeg )
456+ }
455457 }
456458 }
457- }
458459
459- Ok ( ( ) )
460- } ) ?;
461- } else if let Rvalue :: BinaryOp ( op, left, right) = rvalue {
462- trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
463-
464- let r = self . use_ecx ( source_info, |this| {
465- this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
466- } ) ?;
467- if * op == BinOp :: Shr || * op == BinOp :: Shl {
468- let left_bits = place_layout. size . bits ( ) ;
469- let right_size = r. layout . size ;
470- let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
471- if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
472- let source_scope_local_data = match self . source_scope_local_data {
473- ClearCrossCrate :: Set ( ref data) => data,
474- ClearCrossCrate :: Clear => return None ,
475- } ;
476- let dir = if * op == BinOp :: Shr {
477- "right"
478- } else {
479- "left"
480- } ;
481- let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
482- self . tcx . lint_hir (
483- :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
484- hir_id,
485- span,
486- & format ! ( "attempt to shift {} with overflow" , dir) ) ;
487- return None ;
488- }
460+ Ok ( ( ) )
461+ } ) ?;
489462 }
490- self . use_ecx ( source_info, |this| {
491- let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
492- let ( _, overflow, _ty) = this. ecx . overflowing_binary_op ( * op, l, r) ?;
493-
494- // We check overflow in debug mode already
495- // so should only check in release mode.
496- if !this. tcx . sess . overflow_checks ( ) && overflow {
497- let err = err_panic ! ( Overflow ( * op) ) . into ( ) ;
498- return Err ( err) ;
463+
464+ Rvalue :: BinaryOp ( op, left, right) => {
465+ trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
466+
467+ let r = self . use_ecx ( source_info, |this| {
468+ this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
469+ } ) ?;
470+ if * op == BinOp :: Shr || * op == BinOp :: Shl {
471+ let left_bits = place_layout. size . bits ( ) ;
472+ let right_size = r. layout . size ;
473+ let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
474+ if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
475+ let source_scope_local_data = match self . source_scope_local_data {
476+ ClearCrossCrate :: Set ( ref data) => data,
477+ ClearCrossCrate :: Clear => return None ,
478+ } ;
479+ let dir = if * op == BinOp :: Shr {
480+ "right"
481+ } else {
482+ "left"
483+ } ;
484+ let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
485+ self . tcx . lint_hir (
486+ :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
487+ hir_id,
488+ span,
489+ & format ! ( "attempt to shift {} with overflow" , dir) ) ;
490+ return None ;
491+ }
499492 }
493+ self . use_ecx ( source_info, |this| {
494+ let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
495+ let ( _, overflow, _ty) = this. ecx . overflowing_binary_op ( * op, l, r) ?;
496+
497+ // We check overflow in debug mode already
498+ // so should only check in release mode.
499+ if !this. tcx . sess . overflow_checks ( ) && overflow {
500+ let err = err_panic ! ( Overflow ( * op) ) . into ( ) ;
501+ return Err ( err) ;
502+ }
500503
501- Ok ( ( ) )
502- } ) ?;
503- } else if let Rvalue :: Ref ( _, _, place) = rvalue {
504- trace ! ( "checking Ref({:?})" , place) ;
505- // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
506- // from a function argument that hasn't been assigned to in this function.
507- if let Place {
508- base : PlaceBase :: Local ( local) ,
509- projection : box [ ]
510- } = place {
504+ Ok ( ( ) )
505+ } ) ?;
506+ }
507+
508+ Rvalue :: Ref ( _, _, Place { base : PlaceBase :: Local ( local) , projection : box [ ] } ) => {
509+ trace ! ( "checking Ref({:?})" , place) ;
510+ // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
511+ // from a function argument that hasn't been assigned to in this function.
511512 let alive =
512513 if let LocalValue :: Live ( _) = self . ecx . frame ( ) . locals [ * local] . value {
513514 true
@@ -518,12 +519,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
518519 return None ;
519520 }
520521 }
521- } else if let Rvalue :: Aggregate ( _ , operands ) = rvalue {
522- // FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
523- // `SimplifyLocals` doesn't know it can remove.
524- if operands . len ( ) == 0 {
522+
523+ Rvalue :: Aggregate ( _ , operands ) if operands . len ( ) == 0 => {
524+ // FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
525+ // `SimplifyLocals` doesn't know it can remove.
525526 return None ;
526527 }
528+
529+ _ => { }
527530 }
528531
529532 self . use_ecx ( source_info, |this| {
0 commit comments