Skip to content

Commit f1ea2b3

Browse files
committed
Catch arith-overflow explicitly during rustc::middle::const_eval.
This only replaces the conditional arith-overflow asserts with unconditional errors from the guts of const-eval; it does *not* attempt to sanely handle such errors e.g. with a nice error message from `rustc`. So the same test that led me to add this commit are still failing, and must be addressed.
1 parent faf3bcd commit f1ea2b3

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

src/librustc/middle/const_eval.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use syntax::parse::token::InternedString;
2525
use syntax::ptr::P;
2626
use syntax::{ast_map, ast_util, codemap};
2727

28+
use std::num::wrapping::OverflowingOps;
2829
use std::cmp::Ordering;
2930
use std::collections::hash_map::Entry::Vacant;
3031
use std::{i8, i16, i32, i64};
@@ -206,6 +207,33 @@ pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
206207
}
207208
}
208209

210+
fn checked_add_int(a: i64, b: i64) -> Result<const_val, String> {
211+
let (ret, oflo) = a.overflowing_add(b);
212+
if !oflo { Ok(const_int(ret)) } else { Err(format!("constant arithmetic overflow")) }
213+
}
214+
fn checked_sub_int(a: i64, b: i64) -> Result<const_val, String> {
215+
let (ret, oflo) = a.overflowing_sub(b);
216+
if !oflo { Ok(const_int(ret)) } else { Err(format!("constant arithmetic overflow")) }
217+
}
218+
fn checked_mul_int(a: i64, b: i64) -> Result<const_val, String> {
219+
let (ret, oflo) = a.overflowing_mul(b);
220+
if !oflo { Ok(const_int(ret)) } else { Err(format!("constant arithmetic overflow")) }
221+
}
222+
223+
fn checked_add_uint(a: u64, b: u64) -> Result<const_val, String> {
224+
let (ret, oflo) = a.overflowing_add(b);
225+
if !oflo { Ok(const_uint(ret)) } else { Err(format!("constant arithmetic overflow")) }
226+
}
227+
fn checked_sub_uint(a: u64, b: u64) -> Result<const_val, String> {
228+
let (ret, oflo) = a.overflowing_sub(b);
229+
if !oflo { Ok(const_uint(ret)) } else { Err(format!("constant arithmetic overflow")) }
230+
}
231+
fn checked_mul_uint(a: u64, b: u64) -> Result<const_val, String> {
232+
let (ret, oflo) = a.overflowing_mul(b);
233+
if !oflo { Ok(const_uint(ret)) } else { Err(format!("constant arithmetic overflow")) }
234+
}
235+
236+
209237
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
210238
e: &Expr,
211239
ty_hint: Option<Ty<'tcx>>)
@@ -276,9 +304,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
276304
}
277305
};
278306
match op.node {
279-
ast::BiAdd => Ok(const_int(a + b)),
280-
ast::BiSub => Ok(const_int(a - b)),
281-
ast::BiMul => Ok(const_int(a * b)),
307+
ast::BiAdd => checked_add_int(a, b),
308+
ast::BiSub => checked_sub_int(a, b),
309+
ast::BiMul => checked_mul_int(a, b),
282310
ast::BiDiv => {
283311
if b == 0 {
284312
Err("attempted to divide by zero".to_string())
@@ -312,9 +340,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
312340
}
313341
(Ok(const_uint(a)), Ok(const_uint(b))) => {
314342
match op.node {
315-
ast::BiAdd => Ok(const_uint(a + b)),
316-
ast::BiSub => Ok(const_uint(a - b)),
317-
ast::BiMul => Ok(const_uint(a * b)),
343+
ast::BiAdd => checked_add_uint(a, b),
344+
ast::BiSub => checked_sub_uint(a, b),
345+
ast::BiMul => checked_mul_uint(a, b),
318346
ast::BiDiv if b == 0 => {
319347
Err("attempted to divide by zero".to_string())
320348
}

0 commit comments

Comments
 (0)