Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
core::num::wrapping
and fix overflow errors.
Many of the core rust libraries have places that rely on integer wrapping behaviour. These places have been altered to use the wrapping_* methods: * core::hash::sip - A number of macros * core::str - The `maximal_suffix` method in `TwoWaySearcher` * rustc::util::nodemap - Implementation of FnvHash * rustc_back::sha2 - A number of macros and other places * rand::isaac - Isaac64Rng, changed to use the Wrapping helper type Some places had "benign" underflow. This is when underflow or overflow occurs, but the unspecified value is not used due to other conditions. * collections::bit::Bitv - underflow when `self.nbits` is zero. * collections::hash::{map,table} - Underflow when searching an empty table. Did cause undefined behaviour in this case due to an out-of-bounds ptr::offset based on the underflowed index. However the resulting pointers would never be read from. * syntax::ext::deriving::encodable - Underflow when calculating the index of the last field in a variant with no fields. These cases were altered to avoid the underflow, often by moving the underflowing operation to a place where underflow could not happen. There was one case that relied on the fact that unsigned arithmetic and two's complement arithmetic are identical with wrapping semantics. This was changed to use the wrapping_* methods. Finally, the calculation of variant discriminants could overflow if the preceeding discriminant was `U64_MAX`. The logic in `rustc::middle::ty` for this was altered to avoid the overflow completely, while the remaining places were changed to use wrapping methods. This is because `rustc::middle::ty::enum_variants` now throws an error when the calculated discriminant value overflows a `u64`. This behaviour can be triggered by the following code: ``` enum Foo { A = U64_MAX, B } ``` This commit also implements the remaining integer operators for Wrapped<T>.
- Loading branch information
Showing
19 changed files
with
286 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// 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}; | ||
|
||
pub trait WrappingOps { | ||
fn wrapping_add(self, rhs: Self) -> Self; | ||
fn wrapping_sub(self, rhs: Self) -> Self; | ||
fn wrapping_mul(self, rhs: Self) -> Self; | ||
} | ||
|
||
#[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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.