@@ -342,7 +342,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
342342 }
343343 }
344344
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.
346346 #[ inline]
347347 pub fn binary_op (
348348 & self ,
@@ -354,11 +354,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
354354 Ok ( ImmTy :: from_scalar ( val, self . layout_of ( ty) ?) )
355355 }
356356
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 (
358360 & self ,
359361 un_op : mir:: UnOp ,
360362 val : ImmTy < ' tcx , M :: PointerTag > ,
361- ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
363+ ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) > {
362364 use rustc:: mir:: UnOp :: * ;
363365
364366 let layout = val. layout ;
@@ -372,29 +374,45 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
372374 Not => !val,
373375 _ => bug ! ( "Invalid bool op {:?}" , un_op) ,
374376 } ;
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 ) )
376378 }
377379 ty:: Float ( fty) => {
378380 let res = match ( un_op, fty) {
379381 ( Neg , FloatTy :: F32 ) => Scalar :: from_f32 ( -val. to_f32 ( ) ?) ,
380382 ( Neg , FloatTy :: F64 ) => Scalar :: from_f64 ( -val. to_f64 ( ) ?) ,
381383 _ => bug ! ( "Invalid float op {:?}" , un_op) ,
382384 } ;
383- Ok ( ImmTy :: from_scalar ( res, layout) )
385+ Ok ( ( res, false , layout. ty ) )
384386 }
385387 _ => {
386388 assert ! ( layout. ty. is_integral( ) ) ;
387389 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
390392 Neg => {
393+ // arithmetic negation
391394 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)
393402 }
394403 } ;
395404 // res needs tuncating
396- Ok ( ImmTy :: from_uint ( self . truncate ( res, layout) , layout) )
405+ Ok ( ( Scalar :: from_uint ( res, layout. size ) , overflow , layout. ty ) )
397406 }
398407 }
399408 }
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+ }
400418}
0 commit comments