Skip to content

Commit

Permalink
rollup merge of rust-lang#23863: pnkfelix/arith-oflo-const-eval
Browse files Browse the repository at this point in the history
const_eval : add overflow-checking for {`+`, `-`, `*`, `/`, `<<`, `>>`}.

One tricky detail here: There is some duplication of labor between `rustc::middle::const_eval` and `rustc_trans::trans::consts`. It might be good to explore ways to try to factor out the common structure to the two passes (by abstracting over the particular value-representation used in the compile-time interpreter).

----

Update: Rebased atop rust-lang#23841

Fix rust-lang#22531

Fix rust-lang#23030

Fix rust-lang#23221

Fix rust-lang#23235
  • Loading branch information
alexcrichton committed Apr 1, 2015
2 parents 72f5973 + 2a9de1d commit 4f643d7
Show file tree
Hide file tree
Showing 30 changed files with 1,727 additions and 261 deletions.
130 changes: 130 additions & 0 deletions src/libcore/num/wrapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ use intrinsics::{i16_mul_with_overflow, u16_mul_with_overflow};
use intrinsics::{i32_mul_with_overflow, u32_mul_with_overflow};
use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};

use ::{i8,i16,i32,i64,u8,u16,u32,u64};

#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
#[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
pub trait WrappingOps {
Expand All @@ -43,6 +45,12 @@ pub trait OverflowingOps {
fn overflowing_add(self, rhs: Self) -> (Self, bool);
fn overflowing_sub(self, rhs: Self) -> (Self, bool);
fn overflowing_mul(self, rhs: Self) -> (Self, bool);

fn overflowing_div(self, rhs: Self) -> (Self, bool);
fn overflowing_rem(self, rhs: Self) -> (Self, bool);

fn overflowing_shl(self, rhs: u32) -> (Self, bool);
fn overflowing_shr(self, rhs: u32) -> (Self, bool);
}

macro_rules! sh_impl {
Expand Down Expand Up @@ -184,6 +192,20 @@ macro_rules! wrapping_impl {

wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }

mod shift_max {
#![allow(non_upper_case_globals)]

pub const i8: u32 = (1 << 3) - 1;
pub const i16: u32 = (1 << 4) - 1;
pub const i32: u32 = (1 << 5) - 1;
pub const i64: u32 = (1 << 6) - 1;

pub const u8: u32 = i8;
pub const u16: u32 = i16;
pub const u32: u32 = i32;
pub const u64: u32 = i64;
}

macro_rules! overflowing_impl {
($($t:ident)*) => ($(
impl OverflowingOps for $t {
Expand All @@ -205,6 +227,34 @@ macro_rules! overflowing_impl {
concat_idents!($t, _mul_with_overflow)(self, rhs)
}
}

#[inline(always)]
fn overflowing_div(self, rhs: $t) -> ($t, bool) {
if self == $t::MIN && rhs == -1 {
(1, true)
} else {
(self/rhs, false)
}
}
#[inline(always)]
fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
if self == $t::MIN && rhs == -1 {
(0, true)
} else {
(self % rhs, false)
}
}

#[inline(always)]
fn overflowing_shl(self, rhs: u32) -> ($t, bool) {
(self << (rhs & self::shift_max::$t),
(rhs > self::shift_max::$t))
}
#[inline(always)]
fn overflowing_shr(self, rhs: u32) -> ($t, bool) {
(self >> (rhs & self::shift_max::$t),
(rhs > self::shift_max::$t))
}
}
)*)
}
Expand Down Expand Up @@ -234,6 +284,26 @@ impl OverflowingOps for usize {
(res.0 as usize, res.1)
}
}
#[inline(always)]
fn overflowing_div(self, rhs: usize) -> (usize, bool) {
let (r, f) = (self as u64).overflowing_div(rhs as u64);
(r as usize, f)
}
#[inline(always)]
fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
let (r, f) = (self as u64).overflowing_rem(rhs as u64);
(r as usize, f)
}
#[inline(always)]
fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
let (r, f) = (self as u64).overflowing_shl(rhs);
(r as usize, f)
}
#[inline(always)]
fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
let (r, f) = (self as u64).overflowing_shr(rhs);
(r as usize, f)
}
}

#[cfg(target_pointer_width = "32")]
Expand All @@ -259,6 +329,26 @@ impl OverflowingOps for usize {
(res.0 as usize, res.1)
}
}
#[inline(always)]
fn overflowing_div(self, rhs: usize) -> (usize, bool) {
let (r, f) = (self as u32).overflowing_div(rhs as u32);
(r as usize, f)
}
#[inline(always)]
fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
let (r, f) = (self as u32).overflowing_rem(rhs as u32);
(r as usize, f)
}
#[inline(always)]
fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
let (r, f) = (self as u32).overflowing_shl(rhs);
(r as usize, f)
}
#[inline(always)]
fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
let (r, f) = (self as u32).overflowing_shr(rhs);
(r as usize, f)
}
}

#[cfg(target_pointer_width = "64")]
Expand All @@ -284,6 +374,26 @@ impl OverflowingOps for isize {
(res.0 as isize, res.1)
}
}
#[inline(always)]
fn overflowing_div(self, rhs: isize) -> (isize, bool) {
let (r, f) = (self as i64).overflowing_div(rhs as i64);
(r as isize, f)
}
#[inline(always)]
fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
let (r, f) = (self as i64).overflowing_rem(rhs as i64);
(r as isize, f)
}
#[inline(always)]
fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
let (r, f) = (self as i64).overflowing_shl(rhs);
(r as isize, f)
}
#[inline(always)]
fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
let (r, f) = (self as i64).overflowing_shr(rhs);
(r as isize, f)
}
}

#[cfg(target_pointer_width = "32")]
Expand All @@ -309,4 +419,24 @@ impl OverflowingOps for isize {
(res.0 as isize, res.1)
}
}
#[inline(always)]
fn overflowing_div(self, rhs: isize) -> (isize, bool) {
let (r, f) = (self as i32).overflowing_div(rhs as i32);
(r as isize, f)
}
#[inline(always)]
fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
let (r, f) = (self as i32).overflowing_rem(rhs as i32);
(r as isize, f)
}
#[inline(always)]
fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
let (r, f) = (self as i32).overflowing_shl(rhs);
(r as isize, f)
}
#[inline(always)]
fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
let (r, f) = (self as i32).overflowing_shr(rhs);
(r as isize, f)
}
}
2 changes: 1 addition & 1 deletion src/libcoretest/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mod tests {
fn test_overflows() {
assert!(MAX > 0);
assert!(MIN <= 0);
assert!(MIN + MAX + 1 == 0);
assert!((MIN + MAX).wrapping_add(1) == 0);
}

#[test]
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ register_diagnostics! {
E0019,
E0020,
E0022,
E0079, // enum variant: expected signed integer constant
E0080, // enum variant: constant evaluation error
E0109,
E0110,
E0133,
Expand Down Expand Up @@ -128,7 +130,8 @@ register_diagnostics! {
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
E0314, // closure outlives stack frame
E0315, // cannot invoke closure outside of its lifetime
E0316 // nested quantification of lifetimes
E0316, // nested quantification of lifetimes
E0370 // discriminant overflow
}

__build_diagnostic_array! { DIAGNOSTICS }
4 changes: 2 additions & 2 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
})
}

if let Some(ty) = tcx.node_types.borrow().get(&id) {
if let Some(ty) = tcx.node_types().get(&id) {
rbml_w.tag(c::tag_table_node_type, |rbml_w| {
rbml_w.id(id);
rbml_w.emit_ty(ecx, *ty);
Expand Down Expand Up @@ -1884,7 +1884,7 @@ fn decode_side_tables(dcx: &DecodeContext,
let ty = val_dsr.read_ty(dcx);
debug!("inserting ty for node {}: {}",
id, ty_to_string(dcx.tcx, ty));
dcx.tcx.node_types.borrow_mut().insert(id, ty);
dcx.tcx.node_type_insert(id, ty);
}
c::tag_table_item_subst => {
let item_substs = ty::ItemSubsts {
Expand Down
Loading

0 comments on commit 4f643d7

Please sign in to comment.