@@ -13,7 +13,7 @@ use rustc::mir::BinOp;
13
13
use rustc:: mir:: interpret:: { InterpResult , Scalar , GlobalId , ConstValue } ;
14
14
15
15
use super :: {
16
- Machine , PlaceTy , OpTy , InterpCx ,
16
+ Machine , PlaceTy , OpTy , InterpCx , ImmTy ,
17
17
} ;
18
18
19
19
mod caller_location;
@@ -249,6 +249,29 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
249
249
let result = Scalar :: from_uint ( truncated_bits, layout. size ) ;
250
250
self . write_scalar ( result, dest) ?;
251
251
}
252
+
253
+ "ptr_offset_from" => {
254
+ let a = self . read_immediate ( args[ 0 ] ) ?. to_scalar ( ) ?. to_ptr ( ) ?;
255
+ let b = self . read_immediate ( args[ 1 ] ) ?. to_scalar ( ) ?. to_ptr ( ) ?;
256
+ if a. alloc_id != b. alloc_id {
257
+ throw_ub_format ! (
258
+ "ptr_offset_from cannot compute offset of pointers into different \
259
+ allocations.",
260
+ ) ;
261
+ }
262
+ let usize_layout = self . layout_of ( self . tcx . types . usize ) ?;
263
+ let a_offset = ImmTy :: from_uint ( a. offset . bytes ( ) , usize_layout) ;
264
+ let b_offset = ImmTy :: from_uint ( b. offset . bytes ( ) , usize_layout) ;
265
+ let ( val, _overflowed, _ty) = self . overflowing_binary_op (
266
+ BinOp :: Sub , a_offset, b_offset,
267
+ ) ?;
268
+ let pointee_layout = self . layout_of ( substs. type_at ( 0 ) ) ?;
269
+ let isize_layout = self . layout_of ( self . tcx . types . isize ) ?;
270
+ let val = ImmTy :: from_scalar ( val, isize_layout) ;
271
+ let size = ImmTy :: from_int ( pointee_layout. size . bytes ( ) , isize_layout) ;
272
+ self . exact_div ( val, size, dest) ?;
273
+ }
274
+
252
275
"transmute" => {
253
276
self . copy_op_transmute ( args[ 0 ] , dest) ?;
254
277
}
@@ -354,4 +377,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
354
377
return Ok ( false ) ;
355
378
}
356
379
}
380
+
381
+ pub fn exact_div (
382
+ & mut self ,
383
+ a : ImmTy < ' tcx , M :: PointerTag > ,
384
+ b : ImmTy < ' tcx , M :: PointerTag > ,
385
+ dest : PlaceTy < ' tcx , M :: PointerTag > ,
386
+ ) -> InterpResult < ' tcx > {
387
+ // Performs an exact division, resulting in undefined behavior where
388
+ // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`.
389
+ // First, check x % y != 0.
390
+ if self . binary_op ( BinOp :: Rem , a, b) ?. to_bits ( ) ? != 0 {
391
+ // Then, check if `b` is -1, which is the "min_value / -1" case.
392
+ let minus1 = Scalar :: from_int ( -1 , dest. layout . size ) ;
393
+ let b = b. to_scalar ( ) . unwrap ( ) ;
394
+ if b == minus1 {
395
+ throw_ub_format ! ( "exact_div: result of dividing MIN by -1 cannot be represented" )
396
+ } else {
397
+ throw_ub_format ! (
398
+ "exact_div: {} cannot be divided by {} without remainder" ,
399
+ a. to_scalar( ) . unwrap( ) ,
400
+ b,
401
+ )
402
+ }
403
+ }
404
+ self . binop_ignore_overflow ( BinOp :: Div , a, b, dest)
405
+ }
357
406
}
0 commit comments