@@ -342,7 +342,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
342
342
}
343
343
}
344
344
345
- /// Typed version of `checked_binary_op `, returning an `ImmTy`. Also ignores overflows.
345
+ /// Typed version of `overflowing_binary_op `, returning an `ImmTy`. Also ignores overflows.
346
346
#[ inline]
347
347
pub fn binary_op (
348
348
& self ,
@@ -354,11 +354,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
354
354
Ok ( ImmTy :: from_scalar ( val, self . layout_of ( ty) ?) )
355
355
}
356
356
357
- pub fn unary_op (
357
+ /// Returns the result of the specified operation, whether it overflowed, and
358
+ /// the result type.
359
+ pub fn overflowing_unary_op (
358
360
& self ,
359
361
un_op : mir:: UnOp ,
360
362
val : ImmTy < ' tcx , M :: PointerTag > ,
361
- ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
363
+ ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) > {
362
364
use rustc:: mir:: UnOp :: * ;
363
365
364
366
let layout = val. layout ;
@@ -372,29 +374,45 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
372
374
Not => !val,
373
375
_ => bug ! ( "Invalid bool op {:?}" , un_op) ,
374
376
} ;
375
- Ok ( ImmTy :: from_scalar ( Scalar :: from_bool ( res) , self . layout_of ( self . tcx . types . bool ) ? ) )
377
+ Ok ( ( Scalar :: from_bool ( res) , false , self . tcx . types . bool ) )
376
378
}
377
379
ty:: Float ( fty) => {
378
380
let res = match ( un_op, fty) {
379
381
( Neg , FloatTy :: F32 ) => Scalar :: from_f32 ( -val. to_f32 ( ) ?) ,
380
382
( Neg , FloatTy :: F64 ) => Scalar :: from_f64 ( -val. to_f64 ( ) ?) ,
381
383
_ => bug ! ( "Invalid float op {:?}" , un_op) ,
382
384
} ;
383
- Ok ( ImmTy :: from_scalar ( res, layout) )
385
+ Ok ( ( res, false , layout. ty ) )
384
386
}
385
387
_ => {
386
388
assert ! ( layout. ty. is_integral( ) ) ;
387
389
let val = self . force_bits ( val, layout. size ) ?;
388
- let res = match un_op {
389
- Not => !val,
390
+ let ( res, overflow ) = match un_op {
391
+ Not => ( self . truncate ( !val, layout ) , false ) , // bitwise negation, then truncate
390
392
Neg => {
393
+ // arithmetic negation
391
394
assert ! ( layout. abi. is_signed( ) ) ;
392
- ( -( val as i128 ) ) as u128
395
+ let val = self . sign_extend ( val, layout) as i128 ;
396
+ let ( res, overflow) = val. overflowing_neg ( ) ;
397
+ let res = res as u128 ;
398
+ // Truncate to target type.
399
+ // If that truncation loses any information, we have an overflow.
400
+ let truncated = self . truncate ( res, layout) ;
401
+ ( truncated, overflow || self . sign_extend ( truncated, layout) != res)
393
402
}
394
403
} ;
395
404
// res needs tuncating
396
- Ok ( ImmTy :: from_uint ( self . truncate ( res, layout) , layout) )
405
+ Ok ( ( Scalar :: from_uint ( res, layout. size ) , overflow , layout. ty ) )
397
406
}
398
407
}
399
408
}
409
+
410
+ pub fn unary_op (
411
+ & self ,
412
+ un_op : mir:: UnOp ,
413
+ val : ImmTy < ' tcx , M :: PointerTag > ,
414
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
415
+ let ( val, _overflow, ty) = self . overflowing_unary_op ( un_op, val) ?;
416
+ Ok ( ImmTy :: from_scalar ( val, self . layout_of ( ty) ?) )
417
+ }
400
418
}
0 commit comments