Skip to content

Commit 894306e

Browse files
committed
refactor pointer arithmetic handling
1 parent 6eafb10 commit 894306e

File tree

1 file changed

+29
-28
lines changed

1 file changed

+29
-28
lines changed

src/operator.rs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc::ty::{self, Ty};
33

44
use error::{EvalError, EvalResult};
55
use eval_context::EvalContext;
6+
use memory::Pointer;
67
use lvalue::Lvalue;
78
use value::{
89
PrimVal,
@@ -130,19 +131,6 @@ macro_rules! f64_arithmetic {
130131
)
131132
}
132133

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-
146134
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
147135
/// Returns the result of the specified operation and whether it overflowed.
148136
pub fn binary_op(
@@ -202,27 +190,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
202190
}
203191
}
204192
// These work if one operand is a pointer, the other an integer
205-
Sub
193+
Add | Sub
206194
if left_kind == right_kind && (left_kind == usize || left_kind == isize)
207195
&& 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));
219199
}
220200
Add
221201
if left_kind == right_kind && (left_kind == usize || left_kind == isize)
222202
&& 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));
226206
}
227207
_ => {}
228208
}
@@ -300,6 +280,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
300280

301281
Ok((val, false))
302282
}
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+
}
303304
}
304305

305306
pub fn unary_op<'tcx>(

0 commit comments

Comments
 (0)