@@ -8,7 +8,7 @@ use rustc::hir::def::DefKind;
8
8
use rustc:: hir:: def_id:: DefId ;
9
9
use rustc:: mir:: {
10
10
AggregateKind , Constant , Location , Place , PlaceBase , Body , Operand , Rvalue ,
11
- Local , NullOp , UnOp , StatementKind , Statement , LocalKind ,
11
+ Local , UnOp , StatementKind , Statement , LocalKind ,
12
12
TerminatorKind , Terminator , ClearCrossCrate , SourceInfo , BinOp ,
13
13
SourceScope , SourceScopeLocalData , LocalDecl , BasicBlock ,
14
14
} ;
@@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
118
118
struct ConstPropMachine ;
119
119
120
120
impl < ' mir , ' tcx > interpret:: Machine < ' mir , ' tcx > for ConstPropMachine {
121
- type MemoryKinds = !;
121
+ type MemoryKinds = !;
122
122
type PointerTag = ( ) ;
123
123
type ExtraFnVal = !;
124
124
@@ -459,97 +459,81 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
459
459
) -> Option < Const < ' tcx > > {
460
460
let span = source_info. span ;
461
461
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
-
479
462
// 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
+ }
497
482
}
498
483
}
499
- }
500
484
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
+ } ) ?;
531
487
}
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
+ }
541
517
}
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
+ }
542
528
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.
553
537
let alive =
554
538
if let LocalValue :: Live ( _) = self . ecx . frame ( ) . locals [ * local] . value {
555
539
true
@@ -560,6 +544,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
560
544
return None ;
561
545
}
562
546
}
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
+ _ => { }
563
555
}
564
556
565
557
self . use_ecx ( source_info, |this| {
0 commit comments