@@ -8,7 +8,7 @@ use rustc::hir::def::DefKind;
88use rustc:: hir:: def_id:: DefId ;
99use rustc:: mir:: {
1010 AggregateKind , Constant , Location , Place , PlaceBase , Body , Operand , Rvalue ,
11- Local , NullOp , UnOp , StatementKind , Statement , LocalKind ,
11+ Local , UnOp , StatementKind , Statement , LocalKind ,
1212 TerminatorKind , Terminator , ClearCrossCrate , SourceInfo , BinOp ,
1313 SourceScope , SourceScopeLocalData , LocalDecl , BasicBlock ,
1414} ;
@@ -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
@@ -459,97 +459,81 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
459459 ) -> Option < Const < ' tcx > > {
460460 let span = source_info. span ;
461461
462- // if this isn't a supported operation, then return None
463- match rvalue {
464- Rvalue :: Repeat ( ..) |
465- Rvalue :: Aggregate ( ..) |
466- Rvalue :: NullaryOp ( NullOp :: Box , _) |
467- Rvalue :: Discriminant ( ..) => return None ,
468-
469- Rvalue :: Use ( _) |
470- Rvalue :: Len ( _) |
471- Rvalue :: Cast ( ..) |
472- Rvalue :: NullaryOp ( ..) |
473- Rvalue :: CheckedBinaryOp ( ..) |
474- Rvalue :: Ref ( ..) |
475- Rvalue :: UnaryOp ( ..) |
476- Rvalue :: BinaryOp ( ..) => { }
477- }
478-
479462 // perform any special checking for specific Rvalue types
480- if let Rvalue :: UnaryOp ( op, arg) = rvalue {
481- trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
482- let overflow_check = self . tcx . sess . overflow_checks ( ) ;
483-
484- self . use_ecx ( source_info, |this| {
485- // We check overflow in debug mode already
486- // so should only check in release mode.
487- if * op == UnOp :: Neg && !overflow_check {
488- let ty = arg. ty ( & this. local_decls , this. tcx ) ;
489-
490- if ty. is_integral ( ) {
491- let arg = this. ecx . eval_operand ( arg, None ) ?;
492- let prim = this. ecx . read_immediate ( arg) ?;
493- // Need to do overflow check here: For actual CTFE, MIR
494- // generation emits code that does this before calling the op.
495- if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
496- 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+ }
497482 }
498483 }
499- }
500484
501- Ok ( ( ) )
502- } ) ?;
503- } else if let Rvalue :: BinaryOp ( op, left, right) = rvalue {
504- trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
505-
506- let r = self . use_ecx ( source_info, |this| {
507- this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
508- } ) ?;
509- if * op == BinOp :: Shr || * op == BinOp :: Shl {
510- let left_bits = place_layout. size . bits ( ) ;
511- let right_size = r. layout . size ;
512- let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
513- if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
514- let source_scope_local_data = match self . source_scope_local_data {
515- ClearCrossCrate :: Set ( ref data) => data,
516- ClearCrossCrate :: Clear => return None ,
517- } ;
518- let dir = if * op == BinOp :: Shr {
519- "right"
520- } else {
521- "left"
522- } ;
523- let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
524- self . tcx . lint_hir (
525- :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
526- hir_id,
527- span,
528- & format ! ( "attempt to shift {} with overflow" , dir) ) ;
529- return None ;
530- }
485+ Ok ( ( ) )
486+ } ) ?;
531487 }
532- self . use_ecx ( source_info, |this| {
533- let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
534- let ( _, overflow, _ty) = this. ecx . overflowing_binary_op ( * op, l, r) ?;
535-
536- // We check overflow in debug mode already
537- // so should only check in release mode.
538- if !this. tcx . sess . overflow_checks ( ) && overflow {
539- let err = err_panic ! ( Overflow ( * op) ) . into ( ) ;
540- 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+ }
541517 }
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+ }
542528
543- Ok ( ( ) )
544- } ) ?;
545- } else if let Rvalue :: Ref ( _, _, place) = rvalue {
546- trace ! ( "checking Ref({:?})" , place) ;
547- // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
548- // from a function argument that hasn't been assigned to in this function.
549- if let Place {
550- base : PlaceBase :: Local ( local) ,
551- projection : box [ ]
552- } = 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.
553537 let alive =
554538 if let LocalValue :: Live ( _) = self . ecx . frame ( ) . locals [ * local] . value {
555539 true
@@ -560,6 +544,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
560544 return None ;
561545 }
562546 }
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.
551+ return None ;
552+ }
553+
554+ _ => { }
563555 }
564556
565557 self . use_ecx ( source_info, |this| {
0 commit comments