@@ -134,9 +134,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
134134 let mut r = r as u32 ;
135135 let size = left_layout. size ;
136136 oflo |= r >= size. bits ( ) as u32 ;
137- if oflo {
138- r %= size. bits ( ) as u32 ;
139- }
137+ r %= size. bits ( ) as u32 ;
140138 let result = if signed {
141139 let l = self . sign_extend ( l, left_layout) as i128 ;
142140 let result = match bin_op {
@@ -168,6 +166,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
168166 )
169167 }
170168
169+ let size = left_layout. size ;
170+
171171 // Operations that need special treatment for signed integers
172172 if left_layout. abi . is_signed ( ) {
173173 let op: Option < fn ( & i128 , & i128 ) -> bool > = match bin_op {
@@ -195,32 +195,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
195195 if let Some ( op) = op {
196196 let l128 = self . sign_extend ( l, left_layout) as i128 ;
197197 let r = self . sign_extend ( r, right_layout) as i128 ;
198- let size = left_layout. size ;
198+ // We need a special check for overflowing remainder:
199+ // "int_min % -1" overflows and returns 0, but after casting things to a larger int
200+ // type it does *not* overflow nor give an unrepresentable result!
199201 match bin_op {
200- Rem | Div => {
201- // int_min / -1
202+ Rem => {
202203 if r == -1 && l == ( 1 << ( size. bits ( ) - 1 ) ) {
203- return Ok ( ( Scalar :: from_uint ( l , size) , true , left_layout. ty ) ) ;
204+ return Ok ( ( Scalar :: from_int ( 0 , size) , true , left_layout. ty ) ) ;
204205 }
205206 }
206207 _ => { }
207208 }
208- trace ! ( "{}, {}, {}" , l, l128, r) ;
209- let ( result, mut oflo) = op ( l128, r) ;
210- trace ! ( "{}, {}" , result, oflo) ;
211- if !oflo && size. bits ( ) != 128 {
212- let max = 1 << ( size. bits ( ) - 1 ) ;
213- oflo = result >= max || result < -max;
214- }
215- // this may be out-of-bounds for the result type, so we have to truncate ourselves
209+
210+ let ( result, oflo) = op ( l128, r) ;
211+ // This may be out-of-bounds for the result type, so we have to truncate ourselves.
212+ // If that truncation loses any information, we have an overflow.
216213 let result = result as u128 ;
217214 let truncated = self . truncate ( result, left_layout) ;
218- return Ok ( ( Scalar :: from_uint ( truncated, size) , oflo, left_layout. ty ) ) ;
215+ return Ok ( (
216+ Scalar :: from_uint ( truncated, size) ,
217+ oflo || self . sign_extend ( truncated, left_layout) != result,
218+ left_layout. ty ,
219+ ) ) ;
219220 }
220221 }
221222
222- let size = left_layout. size ;
223-
224223 let ( val, ty) = match bin_op {
225224 Eq => ( Scalar :: from_bool ( l == r) , self . tcx . types . bool ) ,
226225 Ne => ( Scalar :: from_bool ( l != r) , self . tcx . types . bool ) ,
@@ -247,6 +246,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
247246 _ => bug ! ( ) ,
248247 } ;
249248 let ( result, oflo) = op ( l, r) ;
249+ // Truncate to target type.
250+ // If that truncation loses any information, we have an overflow.
250251 let truncated = self . truncate ( result, left_layout) ;
251252 return Ok ( (
252253 Scalar :: from_uint ( truncated, size) ,
@@ -341,7 +342,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
341342 }
342343 }
343344
344- /// 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.
345346 #[ inline]
346347 pub fn binary_op (
347348 & self ,
@@ -353,11 +354,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
353354 Ok ( ImmTy :: from_scalar ( val, self . layout_of ( ty) ?) )
354355 }
355356
356- 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 (
357360 & self ,
358361 un_op : mir:: UnOp ,
359362 val : ImmTy < ' tcx , M :: PointerTag > ,
360- ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
363+ ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) > {
361364 use rustc:: mir:: UnOp :: * ;
362365
363366 let layout = val. layout ;
@@ -371,29 +374,44 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
371374 Not => !val,
372375 _ => bug ! ( "Invalid bool op {:?}" , un_op) ,
373376 } ;
374- 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 ) )
375378 }
376379 ty:: Float ( fty) => {
377380 let res = match ( un_op, fty) {
378381 ( Neg , FloatTy :: F32 ) => Scalar :: from_f32 ( -val. to_f32 ( ) ?) ,
379382 ( Neg , FloatTy :: F64 ) => Scalar :: from_f64 ( -val. to_f64 ( ) ?) ,
380383 _ => bug ! ( "Invalid float op {:?}" , un_op) ,
381384 } ;
382- Ok ( ImmTy :: from_scalar ( res, layout) )
385+ Ok ( ( res, false , layout. ty ) )
383386 }
384387 _ => {
385388 assert ! ( layout. ty. is_integral( ) ) ;
386389 let val = self . force_bits ( val, layout. size ) ?;
387- let res = match un_op {
388- Not => !val,
390+ let ( res, overflow ) = match un_op {
391+ Not => ( self . truncate ( !val, layout ) , false ) , // bitwise negation, then truncate
389392 Neg => {
393+ // arithmetic negation
390394 assert ! ( layout. abi. is_signed( ) ) ;
391- ( -( 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)
392402 }
393403 } ;
394- // res needs tuncating
395- Ok ( ImmTy :: from_uint ( self . truncate ( res, layout) , layout) )
404+ Ok ( ( Scalar :: from_uint ( res, layout. size ) , overflow, layout. ty ) )
396405 }
397406 }
398407 }
408+
409+ pub fn unary_op (
410+ & self ,
411+ un_op : mir:: UnOp ,
412+ val : ImmTy < ' tcx , M :: PointerTag > ,
413+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
414+ let ( val, _overflow, ty) = self . overflowing_unary_op ( un_op, val) ?;
415+ Ok ( ImmTy :: from_scalar ( val, self . layout_of ( ty) ?) )
416+ }
399417}
0 commit comments