@@ -24,7 +24,7 @@ use rustc::ty::layout::{
24
24
25
25
use crate :: interpret:: {
26
26
self , InterpCx , ScalarMaybeUndef , Immediate , OpTy ,
27
- ImmTy , StackPopCleanup , LocalValue , LocalState ,
27
+ StackPopCleanup , LocalValue , LocalState ,
28
28
} ;
29
29
use crate :: const_eval:: {
30
30
CompileTimeInterpreter , error_to_const_error, mk_eval_cx,
@@ -311,102 +311,115 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
311
311
place : & Place < ' tcx > ,
312
312
) -> Option < Const < ' tcx > > {
313
313
let span = source_info. span ;
314
- match * rvalue {
314
+
315
+ // if this isn't a supported operation, then return None
316
+ match rvalue {
315
317
Rvalue :: Repeat ( ..) |
316
318
Rvalue :: Aggregate ( ..) |
317
319
Rvalue :: NullaryOp ( NullOp :: Box , _) |
318
- Rvalue :: Discriminant ( ..) => None ,
320
+ Rvalue :: Discriminant ( ..) => return None ,
319
321
320
322
Rvalue :: Use ( _) |
321
323
Rvalue :: Len ( _) |
322
324
Rvalue :: Cast ( ..) |
323
325
Rvalue :: NullaryOp ( ..) |
324
326
Rvalue :: CheckedBinaryOp ( ..) |
325
- Rvalue :: Ref ( ..) => {
326
- self . use_ecx ( source_info, |this| {
327
- this. ecx . eval_rvalue_into_place ( rvalue, place) ?;
328
- this. ecx . eval_place_to_op ( place, Some ( place_layout) )
329
- } )
330
- } ,
327
+ Rvalue :: Ref ( ..) |
328
+ Rvalue :: UnaryOp ( ..) |
329
+ Rvalue :: BinaryOp ( ..) => { }
330
+ }
331
331
332
- Rvalue :: UnaryOp ( op, ref arg) => {
333
- let overflow_check = self . tcx . sess . overflow_checks ( ) ;
334
-
335
- self . use_ecx ( source_info, |this| {
336
- // We check overflow in debug mode already
337
- // so should only check in release mode.
338
- if op == UnOp :: Neg && !overflow_check {
339
- let ty = arg. ty ( & this. local_decls , this. tcx ) ;
340
-
341
- if ty. is_integral ( ) {
342
- let arg = this. ecx . eval_operand ( arg, None ) ?;
343
- let prim = this. ecx . read_immediate ( arg) ?;
344
- // Need to do overflow check here: For actual CTFE, MIR
345
- // generation emits code that does this before calling the op.
346
- if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
347
- throw_panic ! ( OverflowNeg )
348
- }
332
+ // perform any special checking for specific Rvalue types
333
+ if let Rvalue :: UnaryOp ( op, arg) = rvalue {
334
+ trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
335
+ let overflow_check = self . tcx . sess . overflow_checks ( ) ;
336
+
337
+ self . use_ecx ( source_info, |this| {
338
+ // We check overflow in debug mode already
339
+ // so should only check in release mode.
340
+ if * op == UnOp :: Neg && !overflow_check {
341
+ let ty = arg. ty ( & this. local_decls , this. tcx ) ;
342
+
343
+ if ty. is_integral ( ) {
344
+ let arg = this. ecx . eval_operand ( arg, None ) ?;
345
+ let prim = this. ecx . read_immediate ( arg) ?;
346
+ // Need to do overflow check here: For actual CTFE, MIR
347
+ // generation emits code that does this before calling the op.
348
+ if prim. to_bits ( ) ? == ( 1 << ( prim. layout . size . bits ( ) - 1 ) ) {
349
+ throw_panic ! ( OverflowNeg )
349
350
}
350
351
}
351
-
352
- this. ecx . eval_rvalue_into_place ( rvalue, place) ?;
353
- this. ecx . eval_place_to_op ( place, Some ( place_layout) )
354
- } )
355
- }
356
- Rvalue :: BinaryOp ( op, ref left, ref right) => {
357
- trace ! ( "rvalue binop {:?} for {:?} and {:?}" , op, left, right) ;
358
-
359
- let r = self . use_ecx ( source_info, |this| {
360
- this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
361
- } ) ?;
362
- if op == BinOp :: Shr || op == BinOp :: Shl {
363
- let left_bits = place_layout. size . bits ( ) ;
364
- let right_size = r. layout . size ;
365
- let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
366
- if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
367
- let source_scope_local_data = match self . source_scope_local_data {
368
- ClearCrossCrate :: Set ( ref data) => data,
369
- ClearCrossCrate :: Clear => return None ,
370
- } ;
371
- let dir = if op == BinOp :: Shr {
372
- "right"
373
- } else {
374
- "left"
375
- } ;
376
- let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
377
- self . tcx . lint_hir (
378
- :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
379
- hir_id,
380
- span,
381
- & format ! ( "attempt to shift {} with overflow" , dir) ) ;
382
- return None ;
383
- }
384
352
}
385
- trace ! ( "const evaluating {:?} for {:?} and {:?}" , op, left, right) ;
386
- let val = self . use_ecx ( source_info, |this| {
387
- let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
388
- let ( val, overflow, _ty) = this. ecx . overflowing_binary_op ( op, l, r) ?;
389
-
390
- // We check overflow in debug mode already
391
- // so should only check in release mode.
392
- if !this. tcx . sess . overflow_checks ( ) && overflow {
393
- let err = err_panic ! ( Overflow ( op) ) . into ( ) ;
394
- return Err ( err) ;
395
- }
396
353
397
- let val = ImmTy {
398
- imm : Immediate :: Scalar ( val. into ( ) ) ,
399
- layout : place_layout,
354
+ Ok ( ( ) )
355
+ } ) ?;
356
+ } else if let Rvalue :: BinaryOp ( op, left, right) = rvalue {
357
+ trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
358
+
359
+ let r = self . use_ecx ( source_info, |this| {
360
+ this. ecx . read_immediate ( this. ecx . eval_operand ( right, None ) ?)
361
+ } ) ?;
362
+ if * op == BinOp :: Shr || * op == BinOp :: Shl {
363
+ let left_bits = place_layout. size . bits ( ) ;
364
+ let right_size = r. layout . size ;
365
+ let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
366
+ if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
367
+ let source_scope_local_data = match self . source_scope_local_data {
368
+ ClearCrossCrate :: Set ( ref data) => data,
369
+ ClearCrossCrate :: Clear => return None ,
400
370
} ;
371
+ let dir = if * op == BinOp :: Shr {
372
+ "right"
373
+ } else {
374
+ "left"
375
+ } ;
376
+ let hir_id = source_scope_local_data[ source_info. scope ] . lint_root ;
377
+ self . tcx . lint_hir (
378
+ :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
379
+ hir_id,
380
+ span,
381
+ & format ! ( "attempt to shift {} with overflow" , dir) ) ;
382
+ return None ;
383
+ }
384
+ }
385
+ self . use_ecx ( source_info, |this| {
386
+ let l = this. ecx . read_immediate ( this. ecx . eval_operand ( left, None ) ?) ?;
387
+ let ( _, overflow, _ty) = this. ecx . overflowing_binary_op ( * op, l, r) ?;
388
+
389
+ // We check overflow in debug mode already
390
+ // so should only check in release mode.
391
+ if !this. tcx . sess . overflow_checks ( ) && overflow {
392
+ let err = err_panic ! ( Overflow ( * op) ) . into ( ) ;
393
+ return Err ( err) ;
394
+ }
401
395
402
- let dest = this. ecx . eval_place ( place) ?;
403
- this. ecx . write_immediate ( * val, dest) ?;
404
-
405
- Ok ( val)
406
- } ) ?;
407
- Some ( val. into ( ) )
408
- } ,
396
+ Ok ( ( ) )
397
+ } ) ?;
398
+ } else if let Rvalue :: Ref ( _, _, place) = rvalue {
399
+ trace ! ( "checking Ref({:?})" , place) ;
400
+ // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
401
+ // from a function argument that hasn't been assigned to in this function.
402
+ if let Place {
403
+ base : PlaceBase :: Local ( local) ,
404
+ projection : box [ ]
405
+ } = place {
406
+ let alive =
407
+ if let LocalValue :: Live ( _) = self . ecx . frame ( ) . locals [ * local] . value {
408
+ true
409
+ } else { false } ;
410
+
411
+ if local. as_usize ( ) <= self . ecx . frame ( ) . body . arg_count && !alive {
412
+ trace ! ( "skipping Ref({:?})" , place) ;
413
+ return None ;
414
+ }
415
+ }
409
416
}
417
+
418
+ self . use_ecx ( source_info, |this| {
419
+ trace ! ( "calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})" , rvalue, place) ;
420
+ this. ecx . eval_rvalue_into_place ( rvalue, place) ?;
421
+ this. ecx . eval_place_to_op ( place, Some ( place_layout) )
422
+ } )
410
423
}
411
424
412
425
fn operand_from_scalar ( & self , scalar : Scalar , ty : Ty < ' tcx > , span : Span ) -> Operand < ' tcx > {
0 commit comments