Skip to content

Commit aeb9a2b

Browse files
committed
Add zero check/fail paths on div/mod paths. Close #944.
1 parent aa4fa26 commit aeb9a2b

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

src/rustc/middle/trans/base.rs

+54-11
Original file line numberDiff line numberDiff line change
@@ -1634,11 +1634,38 @@ fn cast_shift_rhs(op: ast::binop,
16341634
}
16351635
}
16361636

1637+
fn fail_if_zero(cx: block, span: span, divmod: ast::binop,
1638+
rhs: ValueRef, rhs_t: ty::t) -> block {
1639+
let text = if divmod == ast::div {
1640+
"divide by zero"
1641+
} else {
1642+
"modulo zero"
1643+
};
1644+
let is_zero = alt ty::get(rhs_t).struct {
1645+
ty::ty_int(t) {
1646+
let zero = C_integral(T_int_ty(cx.ccx(), t), 0u64, False);
1647+
ICmp(cx, lib::llvm::IntEQ, rhs, zero)
1648+
}
1649+
ty::ty_uint(t) {
1650+
let zero = C_integral(T_uint_ty(cx.ccx(), t), 0u64, False);
1651+
ICmp(cx, lib::llvm::IntEQ, rhs, zero)
1652+
}
1653+
_ {
1654+
cx.tcx().sess.bug("fail-if-zero on unexpected type: " +
1655+
ty_to_str(cx.ccx().tcx, rhs_t));
1656+
}
1657+
};
1658+
with_cond(cx, is_zero) {|bcx|
1659+
trans_fail(bcx, some(span), text)
1660+
}
1661+
}
1662+
16371663
// Important to get types for both lhs and rhs, because one might be _|_
16381664
// and the other not.
1639-
fn trans_eager_binop(cx: block, op: ast::binop, lhs: ValueRef,
1665+
fn trans_eager_binop(cx: block, span: span, op: ast::binop, lhs: ValueRef,
16401666
lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t, dest: dest)
16411667
-> block {
1668+
let mut cx = cx;
16421669
let _icx = cx.insn_ctxt("trans_eager_binop");
16431670
if dest == ignore { ret cx; }
16441671
let intype = {
@@ -1667,16 +1694,30 @@ fn trans_eager_binop(cx: block, op: ast::binop, lhs: ValueRef,
16671694
else { Mul(cx, lhs, rhs) }
16681695
}
16691696
ast::div {
1670-
if is_float { FDiv(cx, lhs, rhs) }
1671-
else if ty::type_is_signed(intype) {
1672-
SDiv(cx, lhs, rhs)
1673-
} else { UDiv(cx, lhs, rhs) }
1697+
if is_float {
1698+
FDiv(cx, lhs, rhs)
1699+
} else {
1700+
// Only zero-check integers; fp /0 is NaN
1701+
cx = fail_if_zero(cx, span, op, rhs, rhs_t);
1702+
if ty::type_is_signed(intype) {
1703+
SDiv(cx, lhs, rhs)
1704+
} else {
1705+
UDiv(cx, lhs, rhs)
1706+
}
1707+
}
16741708
}
16751709
ast::rem {
1676-
if is_float { FRem(cx, lhs, rhs) }
1677-
else if ty::type_is_signed(intype) {
1678-
SRem(cx, lhs, rhs)
1679-
} else { URem(cx, lhs, rhs) }
1710+
if is_float {
1711+
FRem(cx, lhs, rhs)
1712+
} else {
1713+
// Only zero-check integers; fp %0 is NaN
1714+
cx = fail_if_zero(cx, span, op, rhs, rhs_t);
1715+
if ty::type_is_signed(intype) {
1716+
SRem(cx, lhs, rhs)
1717+
} else {
1718+
URem(cx, lhs, rhs)
1719+
}
1720+
}
16801721
}
16811722
ast::bitor { Or(cx, lhs, rhs) }
16821723
ast::bitand { And(cx, lhs, rhs) }
@@ -1744,7 +1785,8 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
17441785
_ { }
17451786
}
17461787
}
1747-
ret trans_eager_binop(bcx, op, Load(bcx, lhs_res.val), t, rhs_val, t,
1788+
ret trans_eager_binop(bcx, ex.span,
1789+
op, Load(bcx, lhs_res.val), t, rhs_val, t,
17481790
save_in(lhs_res.val));
17491791
}
17501792

@@ -1885,7 +1927,8 @@ fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr,
18851927
// Remaining cases are eager:
18861928
let lhs_res = trans_temp_expr(bcx, lhs);
18871929
let rhs_res = trans_temp_expr(lhs_res.bcx, rhs);
1888-
ret trans_eager_binop(rhs_res.bcx, op, lhs_res.val,
1930+
ret trans_eager_binop(rhs_res.bcx, ex.span,
1931+
op, lhs_res.val,
18891932
expr_ty(bcx, lhs), rhs_res.val,
18901933
expr_ty(bcx, rhs), dest);
18911934
}

src/test/run-fail/divide-by-zero.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// error-pattern:divide by zero
2+
fn main() {
3+
let y = 0;
4+
let z = 1 / y;
5+
}

src/test/run-fail/mod-zero.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// error-pattern:modulo zero
2+
fn main() {
3+
let y = 0;
4+
let z = 1 % y;
5+
}

0 commit comments

Comments
 (0)