From f1ea2b3094b1c28e64af30e187e31aa82f5ff004 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Feb 2015 00:35:20 +0100 Subject: [PATCH] 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. --- src/librustc/middle/const_eval.rs | 40 ++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 0c9f9d2a530..23844739a6b 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -25,6 +25,7 @@ use syntax::ptr::P; use syntax::{ast_map, ast_util, codemap}; +use std::num::wrapping::OverflowingOps; use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; use std::{i8, i16, i32, i64}; @@ -206,6 +207,33 @@ pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val { } } +fn checked_add_int(a: i64, b: i64) -> Result { + let (ret, oflo) = a.overflowing_add(b); + if !oflo { Ok(const_int(ret)) } else { Err(format!("constant arithmetic overflow")) } +} +fn checked_sub_int(a: i64, b: i64) -> Result { + let (ret, oflo) = a.overflowing_sub(b); + if !oflo { Ok(const_int(ret)) } else { Err(format!("constant arithmetic overflow")) } +} +fn checked_mul_int(a: i64, b: i64) -> Result { + let (ret, oflo) = a.overflowing_mul(b); + if !oflo { Ok(const_int(ret)) } else { Err(format!("constant arithmetic overflow")) } +} + +fn checked_add_uint(a: u64, b: u64) -> Result { + let (ret, oflo) = a.overflowing_add(b); + if !oflo { Ok(const_uint(ret)) } else { Err(format!("constant arithmetic overflow")) } +} +fn checked_sub_uint(a: u64, b: u64) -> Result { + let (ret, oflo) = a.overflowing_sub(b); + if !oflo { Ok(const_uint(ret)) } else { Err(format!("constant arithmetic overflow")) } +} +fn checked_mul_uint(a: u64, b: u64) -> Result { + let (ret, oflo) = a.overflowing_mul(b); + if !oflo { Ok(const_uint(ret)) } else { Err(format!("constant arithmetic overflow")) } +} + + pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, e: &Expr, ty_hint: Option>) @@ -276,9 +304,9 @@ fn fromb(b: bool) -> Result { Ok(const_int(b as i64)) } } }; match op.node { - ast::BiAdd => Ok(const_int(a + b)), - ast::BiSub => Ok(const_int(a - b)), - ast::BiMul => Ok(const_int(a * b)), + ast::BiAdd => checked_add_int(a, b), + ast::BiSub => checked_sub_int(a, b), + ast::BiMul => checked_mul_int(a, b), ast::BiDiv => { if b == 0 { Err("attempted to divide by zero".to_string()) @@ -312,9 +340,9 @@ fn fromb(b: bool) -> Result { Ok(const_int(b as i64)) } } (Ok(const_uint(a)), Ok(const_uint(b))) => { match op.node { - ast::BiAdd => Ok(const_uint(a + b)), - ast::BiSub => Ok(const_uint(a - b)), - ast::BiMul => Ok(const_uint(a * b)), + ast::BiAdd => checked_add_uint(a, b), + ast::BiSub => checked_sub_uint(a, b), + ast::BiMul => checked_mul_uint(a, b), ast::BiDiv if b == 0 => { Err("attempted to divide by zero".to_string()) } -- GitLab