Auto merge of #22532 - pnkfelix:arith-overflow, r=pnkfelix,eddyb

Rebase and follow-through on work done by @cmr and @aatch.

Implements most of rust-lang/rfcs#560. Errors encountered from the checks during building were fixed.

The checks for division, remainder and bit-shifting have not been implemented yet.

See also PR #20795

cc @Aatch ; cc @nikomatsakis
This commit is contained in:
bors
2015-03-03 14:18:03 +00:00
57 changed files with 1189 additions and 375 deletions

View File

@@ -14,7 +14,7 @@
use prelude::*;
use default::Default;
use num::wrapping::WrappingOps;
use super::Hasher;
/// An implementation of SipHash 2-4.
@@ -71,17 +71,17 @@ macro_rules! u8to64_le {
macro_rules! rotl {
($x:expr, $b:expr) =>
(($x << $b) | ($x >> (64 - $b)))
(($x << $b) | ($x >> (64.wrapping_sub($b))))
}
macro_rules! compress {
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
({
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = rotl!($v0, 32);
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = rotl!($v2, 32);
})
}

View File

@@ -546,3 +546,14 @@ extern "rust-intrinsic" {
/// Performs checked `u64` multiplication.
pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
}
// SNAP 880fb89
#[cfg(not(stage0))]
extern "rust-intrinsic" {
/// Returns (a + b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_add<T>(a: T, b: T) -> T;
/// Returns (a - b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_sub<T>(a: T, b: T) -> T;
/// Returns (a * b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_mul<T>(a: T, b: T) -> T;
}

View File

@@ -728,10 +728,11 @@ pub trait IteratorExt: Iterator + Sized {
P: FnMut(Self::Item) -> bool,
Self: ExactSizeIterator + DoubleEndedIterator
{
let mut i = self.len() - 1;
let mut i = self.len();
while let Some(v) = self.next_back() {
if predicate(v) {
return Some(i);
return Some(i - 1);
}
i -= 1;
}
@@ -1129,7 +1130,11 @@ impl<I> RandomAccessIterator for Rev<I> where I: DoubleEndedIterator + RandomAcc
#[inline]
fn idx(&mut self, index: usize) -> Option<<I as Iterator>::Item> {
let amt = self.indexable();
self.iter.idx(amt - index - 1)
if amt > index {
self.iter.idx(amt - index - 1)
} else {
None
}
}
}

View File

@@ -69,6 +69,7 @@
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
#[macro_use]
mod macros;

View File

@@ -15,6 +15,8 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
use self::wrapping::{OverflowingOps, WrappingOps};
use char::CharExt;
use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord};
@@ -30,6 +32,9 @@ use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
use str::{FromStr, StrExt};
#[unstable(feature = "core", reason = "may be removed or relocated")]
pub mod wrapping;
/// A built-in signed or unsigned integer.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Int
@@ -48,6 +53,8 @@ pub trait Int
+ BitXor<Output=Self>
+ Shl<uint, Output=Self>
+ Shr<uint, Output=Self>
+ WrappingOps
+ OverflowingOps
{
/// Returns the `0` value of this integer type.
// FIXME (#5527): Should be an associated constant
@@ -376,11 +383,23 @@ pub trait Int
let mut base = self;
let mut acc: Self = Int::one();
let mut prev_base = self;
let mut base_oflo = false;
while exp > 0 {
if (exp & 1) == 1 {
acc = acc * base;
if base_oflo {
// ensure overflow occurs in the same manner it
// would have otherwise (i.e. signal any exception
// it would have otherwise).
acc = acc * (prev_base * prev_base);
} else {
acc = acc * base;
}
}
base = base * base;
prev_base = base;
let (new_base, new_base_oflo) = base.overflowing_mul(base);
base = new_base;
base_oflo = new_base_oflo;
exp /= 2;
}
acc
@@ -691,12 +710,12 @@ signed_int_impl! { int }
/// A built-in unsigned integer.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait UnsignedInt: Int {
pub trait UnsignedInt: Int + WrappingOps {
/// Returns `true` iff `self == 2^k` for some `k`.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
fn is_power_of_two(self) -> bool {
(self - Int::one()) & self == Int::zero() && !(self == Int::zero())
(self.wrapping_sub(Int::one())) & self == Int::zero() && !(self == Int::zero())
}
/// Returns the smallest power of two greater than or equal to `self`.
@@ -706,7 +725,7 @@ pub trait UnsignedInt: Int {
fn next_power_of_two(self) -> Self {
let bits = size_of::<Self>() * 8;
let one: Self = Int::one();
one << ((bits - (self - one).leading_zeros() as usize) % bits)
one << ((bits - self.wrapping_sub(one).leading_zeros() as usize) % bits)
}
/// Returns the smallest power of two greater than or equal to `n`. If the

View File

@@ -20,6 +20,6 @@ pub const BYTES : u32 = ($bits / 8);
#[stable(feature = "rust1", since = "1.0.0")]
pub const MIN: $T = 0 as $T;
#[stable(feature = "rust1", since = "1.0.0")]
pub const MAX: $T = 0 as $T - 1 as $T;
pub const MAX: $T = !0 as $T;
) }

300
src/libcore/num/wrapping.rs Normal file
View File

@@ -0,0 +1,300 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(missing_docs)]
use ops::*;
#[cfg(not(stage0))]
use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul};
use intrinsics::{i8_add_with_overflow, u8_add_with_overflow};
use intrinsics::{i16_add_with_overflow, u16_add_with_overflow};
use intrinsics::{i32_add_with_overflow, u32_add_with_overflow};
use intrinsics::{i64_add_with_overflow, u64_add_with_overflow};
use intrinsics::{i8_sub_with_overflow, u8_sub_with_overflow};
use intrinsics::{i16_sub_with_overflow, u16_sub_with_overflow};
use intrinsics::{i32_sub_with_overflow, u32_sub_with_overflow};
use intrinsics::{i64_sub_with_overflow, u64_sub_with_overflow};
use intrinsics::{i8_mul_with_overflow, u8_mul_with_overflow};
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};
pub trait WrappingOps {
fn wrapping_add(self, rhs: Self) -> Self;
fn wrapping_sub(self, rhs: Self) -> Self;
fn wrapping_mul(self, rhs: Self) -> Self;
}
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
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);
}
#[cfg(not(stage0))]
macro_rules! wrapping_impl {
($($t:ty)*) => ($(
impl WrappingOps for $t {
#[inline(always)]
fn wrapping_add(self, rhs: $t) -> $t {
unsafe {
overflowing_add(self, rhs)
}
}
#[inline(always)]
fn wrapping_sub(self, rhs: $t) -> $t {
unsafe {
overflowing_sub(self, rhs)
}
}
#[inline(always)]
fn wrapping_mul(self, rhs: $t) -> $t {
unsafe {
overflowing_mul(self, rhs)
}
}
}
)*)
}
#[cfg(stage0)]
macro_rules! wrapping_impl {
($($t:ty)*) => ($(
impl WrappingOps for $t {
#[inline(always)]
fn wrapping_add(self, rhs: $t) -> $t {
self + rhs
}
#[inline(always)]
fn wrapping_sub(self, rhs: $t) -> $t {
self - rhs
}
#[inline(always)]
fn wrapping_mul(self, rhs: $t) -> $t {
self * rhs
}
}
)*)
}
wrapping_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
#[derive(PartialEq,Eq,PartialOrd,Ord,Clone,Copy)]
pub struct Wrapping<T>(pub T);
impl<T:WrappingOps> Add for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn add(self, other: Wrapping<T>) -> Wrapping<T> {
Wrapping(self.0.wrapping_add(other.0))
}
}
impl<T:WrappingOps> Sub for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn sub(self, other: Wrapping<T>) -> Wrapping<T> {
Wrapping(self.0.wrapping_sub(other.0))
}
}
impl<T:WrappingOps> Mul for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn mul(self, other: Wrapping<T>) -> Wrapping<T> {
Wrapping(self.0.wrapping_mul(other.0))
}
}
impl<T:WrappingOps+Not<Output=T>> Not for Wrapping<T> {
type Output = Wrapping<T>;
fn not(self) -> Wrapping<T> {
Wrapping(!self.0)
}
}
impl<T:WrappingOps+BitXor<Output=T>> BitXor for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn bitxor(self, other: Wrapping<T>) -> Wrapping<T> {
Wrapping(self.0 ^ other.0)
}
}
impl<T:WrappingOps+BitOr<Output=T>> BitOr for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn bitor(self, other: Wrapping<T>) -> Wrapping<T> {
Wrapping(self.0 | other.0)
}
}
impl<T:WrappingOps+BitAnd<Output=T>> BitAnd for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn bitand(self, other: Wrapping<T>) -> Wrapping<T> {
Wrapping(self.0 & other.0)
}
}
impl<T:WrappingOps+Shl<uint,Output=T>> Shl<uint> for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn shl(self, other: uint) -> Wrapping<T> {
Wrapping(self.0 << other)
}
}
impl<T:WrappingOps+Shr<uint,Output=T>> Shr<uint> for Wrapping<T> {
type Output = Wrapping<T>;
#[inline(always)]
fn shr(self, other: uint) -> Wrapping<T> {
Wrapping(self.0 >> other)
}
}
macro_rules! overflowing_impl {
($($t:ident)*) => ($(
impl OverflowingOps for $t {
#[inline(always)]
fn overflowing_add(self, rhs: $t) -> ($t, bool) {
unsafe {
concat_idents!($t, _add_with_overflow)(self, rhs)
}
}
#[inline(always)]
fn overflowing_sub(self, rhs: $t) -> ($t, bool) {
unsafe {
concat_idents!($t, _sub_with_overflow)(self, rhs)
}
}
#[inline(always)]
fn overflowing_mul(self, rhs: $t) -> ($t, bool) {
unsafe {
concat_idents!($t, _mul_with_overflow)(self, rhs)
}
}
}
)*)
}
overflowing_impl! { u8 u16 u32 u64 i8 i16 i32 i64 }
#[cfg(target_pointer_width = "64")]
impl OverflowingOps for usize {
#[inline(always)]
fn overflowing_add(self, rhs: usize) -> (usize, bool) {
unsafe {
let res = u64_add_with_overflow(self as u64, rhs as u64);
(res.0 as usize, res.1)
}
}
#[inline(always)]
fn overflowing_sub(self, rhs: usize) -> (usize, bool) {
unsafe {
let res = u64_sub_with_overflow(self as u64, rhs as u64);
(res.0 as usize, res.1)
}
}
#[inline(always)]
fn overflowing_mul(self, rhs: usize) -> (usize, bool) {
unsafe {
let res = u64_mul_with_overflow(self as u64, rhs as u64);
(res.0 as usize, res.1)
}
}
}
#[cfg(target_pointer_width = "32")]
impl OverflowingOps for usize {
#[inline(always)]
fn overflowing_add(self, rhs: usize) -> (usize, bool) {
unsafe {
let res = u32_add_with_overflow(self as u32, rhs as u32);
(res.0 as usize, res.1)
}
}
#[inline(always)]
fn overflowing_sub(self, rhs: usize) -> (usize, bool) {
unsafe {
let res = u32_sub_with_overflow(self as u32, rhs as u32);
(res.0 as usize, res.1)
}
}
#[inline(always)]
fn overflowing_mul(self, rhs: usize) -> (usize, bool) {
unsafe {
let res = u32_mul_with_overflow(self as u32, rhs as u32);
(res.0 as usize, res.1)
}
}
}
#[cfg(target_pointer_width = "64")]
impl OverflowingOps for isize {
#[inline(always)]
fn overflowing_add(self, rhs: isize) -> (isize, bool) {
unsafe {
let res = i64_add_with_overflow(self as i64, rhs as i64);
(res.0 as isize, res.1)
}
}
#[inline(always)]
fn overflowing_sub(self, rhs: isize) -> (isize, bool) {
unsafe {
let res = i64_sub_with_overflow(self as i64, rhs as i64);
(res.0 as isize, res.1)
}
}
#[inline(always)]
fn overflowing_mul(self, rhs: isize) -> (isize, bool) {
unsafe {
let res = i64_mul_with_overflow(self as i64, rhs as i64);
(res.0 as isize, res.1)
}
}
}
#[cfg(target_pointer_width = "32")]
impl OverflowingOps for isize {
#[inline(always)]
fn overflowing_add(self, rhs: isize) -> (isize, bool) {
unsafe {
let res = i32_add_with_overflow(self as i32, rhs as i32);
(res.0 as isize, res.1)
}
}
#[inline(always)]
fn overflowing_sub(self, rhs: isize) -> (isize, bool) {
unsafe {
let res = i32_sub_with_overflow(self as i32, rhs as i32);
(res.0 as isize, res.1)
}
}
#[inline(always)]
fn overflowing_mul(self, rhs: isize) -> (isize, bool) {
unsafe {
let res = i32_mul_with_overflow(self as i32, rhs as i32);
(res.0 as isize, res.1)
}
}
}

View File

@@ -841,6 +841,7 @@ impl TwoWaySearcher {
#[inline]
#[allow(dead_code)]
fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
use num::wrapping::WrappingOps;
let mut left = -1; // Corresponds to i in the paper
let mut right = 0; // Corresponds to j in the paper
let mut offset = 1; // Corresponds to k in the paper
@@ -850,17 +851,17 @@ impl TwoWaySearcher {
let a;
let b;
if reversed {
a = arr[left + offset];
a = arr[left.wrapping_add(offset)];
b = arr[right + offset];
} else {
a = arr[right + offset];
b = arr[left + offset];
b = arr[left.wrapping_add(offset)];
}
if a < b {
// Suffix is smaller, period is entire prefix so far.
right += offset;
offset = 1;
period = right - left;
period = right.wrapping_sub(left);
} else if a == b {
// Advance through repetition of the current period.
if offset == period {
@@ -877,7 +878,7 @@ impl TwoWaySearcher {
period = 1;
}
}
(left + 1, period)
(left.wrapping_add(1), period)
}
}