@@ -3,6 +3,7 @@ use rustc::ty::{self, Ty};
3
3
4
4
use error:: { EvalError , EvalResult } ;
5
5
use eval_context:: EvalContext ;
6
+ use memory:: Pointer ;
6
7
use lvalue:: Lvalue ;
7
8
use value:: {
8
9
PrimVal ,
@@ -130,19 +131,6 @@ macro_rules! f64_arithmetic {
130
131
)
131
132
}
132
133
133
- macro_rules! ptr_add {
134
- ( $signed: expr, $ptr: expr, $int: expr, $layout: expr) => ( {
135
- let ptr = $ptr;
136
- let int = $int;
137
- let ( res, over) = if $signed {
138
- ptr. overflowing_signed_offset( int as i128 , $layout)
139
- } else {
140
- ptr. overflowing_offset( int as u64 , $layout)
141
- } ;
142
- ( PrimVal :: Ptr ( res) , over)
143
- } )
144
- }
145
-
146
134
impl < ' a , ' tcx > EvalContext < ' a , ' tcx > {
147
135
/// Returns the result of the specified operation and whether it overflowed.
148
136
pub fn binary_op (
@@ -202,27 +190,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
202
190
}
203
191
}
204
192
// These work if one operand is a pointer, the other an integer
205
- Sub
193
+ Add | Sub
206
194
if left_kind == right_kind && ( left_kind == usize || left_kind == isize)
207
195
&& left. is_ptr ( ) && right. is_bytes ( ) => {
208
- let left = left. to_ptr ( ) ?;
209
- let right = right. to_bytes ( ) ? as i128 ; // this cast is fine as the kind is max. 64bit
210
- let ( res, over) = left. overflowing_signed_offset ( -right, self . memory . layout ) ;
211
- return Ok ( ( PrimVal :: Ptr ( res) , over) )
212
- }
213
- Add
214
- if left_kind == right_kind && ( left_kind == usize || left_kind == isize)
215
- && left. is_ptr ( ) && right. is_bytes ( ) => {
216
- let left = left. to_ptr ( ) ?;
217
- let right = right. to_bytes ( ) ?;
218
- return Ok ( ptr_add ! ( left_kind == isize , left, right, self . memory. layout) ) ;
196
+ // Cast to i128 is fine as we checked the kind to be ptr-sized
197
+ let ( res, over) = self . ptr_int_arithmetic ( bin_op, left. to_ptr ( ) ?, right. to_bytes ( ) ? as i128 , left_kind == isize) ?;
198
+ return Ok ( ( PrimVal :: Ptr ( res) , over) ) ;
219
199
}
220
200
Add
221
201
if left_kind == right_kind && ( left_kind == usize || left_kind == isize)
222
202
&& left. is_bytes ( ) && right. is_ptr ( ) => {
223
- let left = left . to_bytes ( ) ? ;
224
- let right = right. to_ptr ( ) ?;
225
- return Ok ( ptr_add ! ( left_kind == isize , right , left , self . memory . layout ) ) ;
203
+ // This is a commutative operation, just swap the operands
204
+ let ( res , over ) = self . ptr_int_arithmetic ( bin_op , right. to_ptr ( ) ? , left . to_bytes ( ) ? as i128 , left_kind == isize ) ?;
205
+ return Ok ( ( PrimVal :: Ptr ( res ) , over ) ) ;
226
206
}
227
207
_ => { }
228
208
}
@@ -300,6 +280,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
300
280
301
281
Ok ( ( val, false ) )
302
282
}
283
+
284
+ fn ptr_int_arithmetic (
285
+ & self ,
286
+ bin_op : mir:: BinOp ,
287
+ left : Pointer ,
288
+ right : i128 ,
289
+ signed : bool ,
290
+ ) -> EvalResult < ' tcx , ( Pointer , bool ) > {
291
+ use rustc:: mir:: BinOp :: * ;
292
+
293
+ Ok ( match bin_op {
294
+ Sub =>
295
+ // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter
296
+ left. overflowing_signed_offset ( -right, self . memory . layout ) ,
297
+ Add if signed =>
298
+ left. overflowing_signed_offset ( right, self . memory . layout ) ,
299
+ Add if !signed =>
300
+ left. overflowing_offset ( right as u64 , self . memory . layout ) ,
301
+ _ => bug ! ( "ptr_int_arithmetic called on unsupported operation" )
302
+ } )
303
+ }
303
304
}
304
305
305
306
pub fn unary_op < ' tcx > (
0 commit comments