Skip to content

Commit

Permalink
Auto merge of #24500 - pnkfelix:oflo-checked-neg, r=<try>
Browse files Browse the repository at this point in the history
Add conditional overflow-checking to signed negate operator.

I argue this can land independently of #24420 , because one can write the implementation of `wrapped_neg()` inline if necessary (as illustrated in two cases on this PR).

This needs to go into beta channel.
  • Loading branch information
bors committed Apr 16, 2015
2 parents ac2b6f6 + f9c6780 commit 2e51e09
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 20 deletions.
7 changes: 6 additions & 1 deletion src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1261,7 +1261,12 @@ macro_rules! int_impl {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn abs(self) -> $T {
if self.is_negative() { -self } else { self }
if self.is_negative() {
// FIXME (#24420) use wrapping_neg instead after it lands.
(!self).wrapping_add(1)
} else {
self
}
}

/// Returns a number representing sign of `self`.
Expand Down
35 changes: 20 additions & 15 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,25 @@ fn cast_shift_rhs<F, G>(op: ast::BinOp_,
}
}

pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
val_t: Ty<'tcx>) -> (Type, u64) {
match val_t.sty {
ty::ty_int(t) => {
let llty = Type::int_from_ty(cx.ccx(), t);
let min = match t {
ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
ast::TyIs => i64::MIN as u64,
ast::TyI8 => i8::MIN as u64,
ast::TyI16 => i16::MIN as u64,
ast::TyI32 => i32::MIN as u64,
ast::TyI64 => i64::MIN as u64,
};
(llty, min)
}
_ => unreachable!(),
}
}

pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
cx: Block<'blk, 'tcx>,
call_info: NodeIdAndSpan,
Expand Down Expand Up @@ -620,21 +639,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
// signed division/remainder which would trigger overflow. For unsigned
// integers, no action beyond checking for zero need be taken.
if is_signed {
let (llty, min) = match rhs_t.sty {
ty::ty_int(t) => {
let llty = Type::int_from_ty(cx.ccx(), t);
let min = match t {
ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
ast::TyIs => i64::MIN as u64,
ast::TyI8 => i8::MIN as u64,
ast::TyI16 => i16::MIN as u64,
ast::TyI32 => i32::MIN as u64,
ast::TyI64 => i64::MIN as u64,
};
(llty, min)
}
_ => unreachable!(),
};
let (llty, min) = llty_and_min_for_signed_ty(cx, rhs_t);
let minus_one = ICmp(bcx, llvm::IntEQ, rhs,
C_integral(llty, !0, false), debug_loc);
with_cond(bcx, minus_one, |bcx| {
Expand Down
21 changes: 18 additions & 3 deletions src/librustc_trans/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1530,11 +1530,26 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ast::UnNeg => {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
let val = datum.to_llscalarish(bcx);
let llneg = {
let (bcx, llneg) = {
if ty::type_is_fp(un_ty) {
FNeg(bcx, val, debug_loc)
let result = FNeg(bcx, val, debug_loc);
(bcx, result)
} else {
Neg(bcx, val, debug_loc)
let is_signed = ty::type_is_signed(un_ty);
let result = Neg(bcx, val, debug_loc);
let bcx = if bcx.ccx().check_overflow() && is_signed {
let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty);
let is_min = ICmp(bcx, llvm::IntEQ, val,
C_integral(llty, min, true), debug_loc);
with_cond(bcx, is_min, |bcx| {
let msg = InternedString::new(
"attempted to negate with overflow");
controlflow::trans_fail(bcx, expr_info(expr), msg)
})
} else {
bcx
};
(bcx, result)
}
};
immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
Expand Down
3 changes: 2 additions & 1 deletion src/libserialize/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,8 @@ impl<T: Iterator<Item=char>> Parser<T> {
F64Value(res)
} else {
if neg {
let res = -(res as i64);
// FIXME (#24420) use wrapping_neg instead after it lands.
let res = !(res as i64).wrapping_add(1);

// Make sure we didn't underflow.
if res > 0 {
Expand Down

0 comments on commit 2e51e09

Please sign in to comment.