Skip to content

Commit c698a1b

Browse files
committed
Add Wrapping<T> and WrappingOps implementations
Adds a Wrapping<T> wrapper type and a WrappingOps trait for allowing people to explictly opt-in to wrapping integer arithmetic. This commit currently disables overflow checking in the build due to cases of expected overflow triggering the panic.
1 parent 378805c commit c698a1b

File tree

11 files changed

+112
-12
lines changed

11 files changed

+112
-12
lines changed

mk/main.mk

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ endif
157157
# have to worry about the distribution of one file (with its native dynamic
158158
# dependencies)
159159
RUSTFLAGS_STAGE0 += -C prefer-dynamic
160-
RUSTFLAGS_STAGE1 += -C prefer-dynamic
161-
RUST_LIB_FLAGS_ST2 += -C prefer-dynamic
160+
# FIXME: Remove the -Z force-no-overflow-checks flags
161+
RUSTFLAGS_STAGE1 += -C prefer-dynamic -Z force-no-overflow-checks
162+
RUST_LIB_FLAGS_ST2 += -C prefer-dynamic -Z force-no-overflow-checks
162163
RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
163164

164165
# Landing pads require a lot of codegen. We can get through bootstrapping faster

src/libcore/intrinsics.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ extern "rust-intrinsic" {
547547
pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
548548
}
549549

550+
#[cfg(not(stage1))]
550551
extern "rust-intrinsic" {
551552
/// Returns (a + b) mod 2^N, where N is the width of N in bits.
552553
pub fn overflowing_add<T>(a: T, b: T) -> T;
@@ -556,8 +557,6 @@ extern "rust-intrinsic" {
556557
pub fn overflowing_mul<T>(a: T, b: T) -> T;
557558
}
558559

559-
#[cfg(not(stage0))]
560-
561560
/// `TypeId` represents a globally unique identifier for a type
562561
#[lang="type_id"] // This needs to be kept in lockstep with the code in trans/intrinsic.rs and
563562
// middle/lang_items.rs

src/libcore/num/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ use option::Option;
2929
use option::Option::{Some, None};
3030
use str::{FromStr, StrExt};
3131

32+
pub mod wrapping;
33+
3234
/// A built-in signed or unsigned integer.
3335
#[stable]
3436
pub trait Int

src/libcore/num/wrapping.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#![allow(missing_docs)]
2+
3+
use ops::*;
4+
5+
#[cfg(not(stage0))]
6+
use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul};
7+
8+
pub trait WrappingOps {
9+
fn wrapping_add(self, rhs: Self) -> Self;
10+
fn wrapping_sub(self, rhs: Self) -> Self;
11+
fn wrapping_mul(self, rhs: Self) -> Self;
12+
}
13+
14+
#[cfg(not(stage0))]
15+
macro_rules! wrapping_impl {
16+
($($t:ty)*) => ($(
17+
impl WrappingOps for $t {
18+
#[inline(always)]
19+
fn wrapping_add(self, rhs: $t) -> $t {
20+
unsafe {
21+
overflowing_add(self, rhs)
22+
}
23+
}
24+
#[inline(always)]
25+
fn wrapping_sub(self, rhs: $t) -> $t {
26+
unsafe {
27+
overflowing_sub(self, rhs)
28+
}
29+
}
30+
#[inline(always)]
31+
fn wrapping_mul(self, rhs: $t) -> $t {
32+
unsafe {
33+
overflowing_mul(self, rhs)
34+
}
35+
}
36+
}
37+
)*)
38+
}
39+
40+
#[cfg(stage0)]
41+
macro_rules! wrapping_impl {
42+
($($t:ty)*) => ($(
43+
impl WrappingOps for $t {
44+
#[inline(always)]
45+
fn wrapping_add(self, rhs: $t) -> $t {
46+
self + rhs
47+
}
48+
#[inline(always)]
49+
fn wrapping_sub(self, rhs: $t) -> $t {
50+
self - rhs
51+
}
52+
#[inline(always)]
53+
fn wrapping_mul(self, rhs: $t) -> $t {
54+
self * rhs
55+
}
56+
}
57+
)*)
58+
}
59+
60+
wrapping_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
61+
62+
#[derive(PartialEq,Eq,PartialOrd,Ord,Clone)]
63+
pub struct Wrapping<T>(pub T);
64+
65+
impl<T:WrappingOps> Add for Wrapping<T> {
66+
type Output = Wrapping<T>;
67+
68+
#[inline(always)]
69+
fn add(self, other: Wrapping<T>) -> Wrapping<T> {
70+
Wrapping(self.0.wrapping_add(other.0))
71+
}
72+
}
73+
74+
impl<T:WrappingOps> Sub for Wrapping<T> {
75+
type Output = Wrapping<T>;
76+
77+
#[inline(always)]
78+
fn sub(self, other: Wrapping<T>) -> Wrapping<T> {
79+
Wrapping(self.0.wrapping_sub(other.0))
80+
}
81+
}
82+
83+
impl<T:WrappingOps> Mul for Wrapping<T> {
84+
type Output = Wrapping<T>;
85+
86+
#[inline(always)]
87+
fn mul(self, other: Wrapping<T>) -> Wrapping<T> {
88+
Wrapping(self.0.wrapping_mul(other.0))
89+
}
90+
}

src/libcore/ops.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ macro_rules! shr_impl {
773773

774774
shr_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
775775

776+
776777
/// The `Index` trait is used to specify the functionality of indexing operations
777778
/// like `arr[idx]` when used in an immutable context.
778779
///

src/libcore/prelude.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
pub use marker::{Copy, Send, Sized, Sync};
3333
pub use ops::{Drop, Fn, FnMut, FnOnce, FullRange};
3434

35+
pub use num::wrapping::{Wrapping, WrappingOps};
36+
3537
// Reexported functions
3638
pub use iter::range;
3739
pub use mem::drop;

src/librand/isaac.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ impl Isaac64Rng {
307307
let mut $var = 0x9e3779b97f4a7c13;
308308
)
309309
}
310+
310311
init!(a); init!(b); init!(c); init!(d);
311312
init!(e); init!(f); init!(g); init!(h);
312313

src/librustc/session/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ debugging_opts! {
300300
UNSTABLE_OPTIONS,
301301
PRINT_ENUM_SIZES,
302302
FORCE_OVERFLOW_CHECKS,
303-
FORCE_NO_OVERFLOW_CHECKS,
303+
FORCE_NO_OVERFLOW_CHECKS
304304
]
305305
0
306306
}
@@ -354,8 +354,8 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
354354
("unstable-options", "Adds unstable command line options to rustc interface",
355355
UNSTABLE_OPTIONS),
356356
("print-enum-sizes", "Print the size of enums and their variants", PRINT_ENUM_SIZES),
357-
("force-overflow-checks", "Force arithmatic overflow checking", FORCE_OVERFLOW_CHECKS),
358-
("force-no-overflow-checks", "Force arithmatic overflow checking", FORCE_NO_OVERFLOW_CHECKS),
357+
("force-overflow-checks", "Force arithmetic overflow checking on", FORCE_OVERFLOW_CHECKS),
358+
("force-no-overflow-checks", "Force arithmetic overflow checking off", FORCE_NO_OVERFLOW_CHECKS),
359359
]
360360
}
361361

src/librustc_trans/trans/base.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3111,8 +3111,9 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
31113111
let ty::CrateAnalysis { ty_cx: tcx, export_map, reachable, name, .. } = analysis;
31123112
let krate = tcx.map.krate();
31133113

3114-
let check_overflow = tcx.sess.opts.debugging_opts & config::FORCE_OVERFLOW_CHECKS != 0
3115-
|| !attr::contains_name(krate.config[], "ndebug");
3114+
let check_overflow = tcx.sess.opts.debugging_opts & config::FORCE_NO_OVERFLOW_CHECKS == 0
3115+
&& (tcx.sess.opts.debugging_opts & config::FORCE_OVERFLOW_CHECKS != 0
3116+
|| !attr::contains_name(krate.config[], "ndebug"));
31163117

31173118
// Before we touch LLVM, make sure that multithreading is enabled.
31183119
unsafe {

src/librustc_trans/trans/intrinsic.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
506506
with_overflow_intrinsic(bcx, "llvm.umul.with.overflow.i64", ret_ty,
507507
llargs[0], llargs[1]),
508508

509-
(_, "overflowing_add") => Add(bcx, llargs[0], llargs[1])
510-
(_, "overflowing_sub") => Sub(bcx, llargs[0], llargs[1])
511-
(_, "overflowing_mul") => Mul(bcx, llargs[0], llargs[1])
509+
(_, "overflowing_add") => Add(bcx, llargs[0], llargs[1]),
510+
(_, "overflowing_sub") => Sub(bcx, llargs[0], llargs[1]),
511+
(_, "overflowing_mul") => Mul(bcx, llargs[0], llargs[1]),
512512

513513
(_, "return_address") => {
514514
if !fcx.caller_expects_out_pointer {

src/librustc_typeck/check/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5763,6 +5763,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
57635763
(0, vec!(tcx.types.u64, tcx.types.u64),
57645764
ty::mk_tup(tcx, vec!(tcx.types.u64, tcx.types.bool))),
57655765

5766+
"overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
5767+
(1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
5768+
57665769
"return_address" => (0, vec![], ty::mk_imm_ptr(tcx, tcx.types.u8)),
57675770

57685771
"assume" => (0, vec![tcx.types.bool], ty::mk_nil(tcx)),

0 commit comments

Comments
 (0)