Skip to content

Commit 9edbf42

Browse files
committed
rollup merge of #23945: pnkfelix/gate-u-negate
Feature-gate unsigned unary negate. Discussed in weekly meeting here: https://github.com/rust-lang/meeting-minutes/blob/master/weekly-meetings/2015-03-31.md#feature-gate--expr and also in the internals thread here: http://internals.rust-lang.org/t/forbid-unsigned-integer/752
2 parents 2e3b0c0 + f86318d commit 9edbf42

File tree

32 files changed

+146
-48
lines changed

32 files changed

+146
-48
lines changed

src/libcollections/slice.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ impl Iterator for ElementSwaps {
11351135
// #[inline]
11361136
fn next(&mut self) -> Option<(usize, usize)> {
11371137
fn new_pos_wrapping(i: usize, s: Direction) -> usize {
1138-
i.wrapping_add(match s { Pos => 1, Neg => -1 })
1138+
i.wrapping_add(match s { Pos => 1, Neg => !0 /* aka -1 */ })
11391139
}
11401140

11411141
fn new_pos(i: usize, s: Direction) -> usize {

src/libcollectionstest/slice.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ fn test_bytes_set_memory() {
10891089
#[should_panic]
10901090
fn test_overflow_does_not_cause_segfault() {
10911091
let mut v = vec![];
1092-
v.reserve_exact(-1);
1092+
v.reserve_exact(!0);
10931093
v.push(1);
10941094
v.push(2);
10951095
}
@@ -1098,7 +1098,7 @@ fn test_overflow_does_not_cause_segfault() {
10981098
#[should_panic]
10991099
fn test_overflow_does_not_cause_segfault_managed() {
11001100
let mut v = vec![Rc::new(1)];
1101-
v.reserve_exact(-1);
1101+
v.reserve_exact(!0);
11021102
v.push(Rc::new(2));
11031103
}
11041104

src/libcore/atomic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ pub const ATOMIC_USIZE_INIT: AtomicUsize =
161161
AtomicUsize { v: UnsafeCell { value: 0, } };
162162

163163
// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
164-
const UINT_TRUE: usize = -1;
164+
const UINT_TRUE: usize = !0;
165165

166166
impl AtomicBool {
167167
/// Creates a new `AtomicBool`.

src/libcore/cell.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ pub enum BorrowState {
287287
// (will not outgrow its range since `usize` is the size of the address space)
288288
type BorrowFlag = usize;
289289
const UNUSED: BorrowFlag = 0;
290-
const WRITING: BorrowFlag = -1;
290+
const WRITING: BorrowFlag = !0;
291291

292292
impl<T> RefCell<T> {
293293
/// Creates a new `RefCell` containing `value`.

src/libcore/num/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ macro_rules! uint_impl {
516516
fn min_value() -> $T { 0 }
517517

518518
#[inline]
519-
fn max_value() -> $T { -1 }
519+
fn max_value() -> $T { !0 }
520520

521521
#[inline]
522522
fn count_ones(self) -> u32 {

src/libcore/num/wrapping.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use intrinsics::{i16_mul_with_overflow, u16_mul_with_overflow};
3030
use intrinsics::{i32_mul_with_overflow, u32_mul_with_overflow};
3131
use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};
3232

33-
use ::{i8,i16,i32,i64,u8,u16,u32,u64};
33+
use ::{i8,i16,i32,i64};
3434

3535
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
3636
#[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
@@ -206,7 +206,7 @@ mod shift_max {
206206
pub const u64: u32 = i64;
207207
}
208208

209-
macro_rules! overflowing_impl {
209+
macro_rules! signed_overflowing_impl {
210210
($($t:ident)*) => ($(
211211
impl OverflowingOps for $t {
212212
#[inline(always)]
@@ -259,7 +259,53 @@ macro_rules! overflowing_impl {
259259
)*)
260260
}
261261

262-
overflowing_impl! { u8 u16 u32 u64 i8 i16 i32 i64 }
262+
macro_rules! unsigned_overflowing_impl {
263+
($($t:ident)*) => ($(
264+
impl OverflowingOps for $t {
265+
#[inline(always)]
266+
fn overflowing_add(self, rhs: $t) -> ($t, bool) {
267+
unsafe {
268+
concat_idents!($t, _add_with_overflow)(self, rhs)
269+
}
270+
}
271+
#[inline(always)]
272+
fn overflowing_sub(self, rhs: $t) -> ($t, bool) {
273+
unsafe {
274+
concat_idents!($t, _sub_with_overflow)(self, rhs)
275+
}
276+
}
277+
#[inline(always)]
278+
fn overflowing_mul(self, rhs: $t) -> ($t, bool) {
279+
unsafe {
280+
concat_idents!($t, _mul_with_overflow)(self, rhs)
281+
}
282+
}
283+
284+
#[inline(always)]
285+
fn overflowing_div(self, rhs: $t) -> ($t, bool) {
286+
(self/rhs, false)
287+
}
288+
#[inline(always)]
289+
fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
290+
(self % rhs, false)
291+
}
292+
293+
#[inline(always)]
294+
fn overflowing_shl(self, rhs: u32) -> ($t, bool) {
295+
(self << (rhs & self::shift_max::$t),
296+
(rhs > self::shift_max::$t))
297+
}
298+
#[inline(always)]
299+
fn overflowing_shr(self, rhs: u32) -> ($t, bool) {
300+
(self >> (rhs & self::shift_max::$t),
301+
(rhs > self::shift_max::$t))
302+
}
303+
}
304+
)*)
305+
}
306+
307+
signed_overflowing_impl! { i8 i16 i32 i64 }
308+
unsigned_overflowing_impl! { u8 u16 u32 u64 }
263309

264310
#[cfg(target_pointer_width = "64")]
265311
impl OverflowingOps for usize {

src/libcore/ops.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,8 +482,10 @@ pub trait Neg {
482482
fn neg(self) -> Self::Output;
483483
}
484484

485-
macro_rules! neg_impl {
486-
($($t:ty)*) => ($(
485+
486+
487+
macro_rules! neg_impl_core {
488+
($id:ident => $body:expr, $($t:ty)*) => ($(
487489
#[stable(feature = "rust1", since = "1.0.0")]
488490
#[allow(unsigned_negation)]
489491
impl Neg for $t {
@@ -492,14 +494,28 @@ macro_rules! neg_impl {
492494

493495
#[inline]
494496
#[stable(feature = "rust1", since = "1.0.0")]
495-
fn neg(self) -> $t { -self }
497+
fn neg(self) -> $t { let $id = self; $body }
496498
}
497499

498500
forward_ref_unop! { impl Neg, neg for $t }
499501
)*)
500502
}
501503

502-
neg_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
504+
macro_rules! neg_impl_numeric {
505+
($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} }
506+
}
507+
508+
macro_rules! neg_impl_unsigned {
509+
($($t:ty)*) => {
510+
neg_impl_core!{ x => {
511+
#[cfg(stage0)]
512+
use ::num::wrapping::WrappingOps;
513+
!x.wrapping_add(1)
514+
}, $($t)*} }
515+
}
516+
517+
// neg_impl_unsigned! { usize u8 u16 u32 u64 }
518+
neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 }
503519

504520
/// The `Not` trait is used to specify the functionality of unary `!`.
505521
///

src/libcore/str/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,7 @@ impl TwoWaySearcher {
855855
#[allow(dead_code)]
856856
#[allow(deprecated)]
857857
fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
858-
let mut left: usize = -1; // Corresponds to i in the paper
858+
let mut left: usize = !0; // Corresponds to i in the paper
859859
let mut right = 0; // Corresponds to j in the paper
860860
let mut offset = 1; // Corresponds to k in the paper
861861
let mut period = 1; // Corresponds to p in the paper

src/libcoretest/fmt/num.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,14 @@ fn test_format_int_flags() {
125125
assert!(format!("{:>8x}", 10) == " a");
126126
assert!(format!("{:#08x}", 10) == "0x00000a");
127127
assert!(format!("{:08}", -10) == "-0000010");
128-
assert!(format!("{:x}", -1u8) == "ff");
129-
assert!(format!("{:X}", -1u8) == "FF");
130-
assert!(format!("{:b}", -1u8) == "11111111");
131-
assert!(format!("{:o}", -1u8) == "377");
132-
assert!(format!("{:#x}", -1u8) == "0xff");
133-
assert!(format!("{:#X}", -1u8) == "0xFF");
134-
assert!(format!("{:#b}", -1u8) == "0b11111111");
135-
assert!(format!("{:#o}", -1u8) == "0o377");
128+
assert!(format!("{:x}", !0u8) == "ff");
129+
assert!(format!("{:X}", !0u8) == "FF");
130+
assert!(format!("{:b}", !0u8) == "11111111");
131+
assert!(format!("{:o}", !0u8) == "377");
132+
assert!(format!("{:#x}", !0u8) == "0xff");
133+
assert!(format!("{:#X}", !0u8) == "0xFF");
134+
assert!(format!("{:#b}", !0u8) == "0b11111111");
135+
assert!(format!("{:#o}", !0u8) == "0o377");
136136
}
137137

138138
#[test]

src/liblibc/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2865,7 +2865,7 @@ pub mod consts {
28652865
pub const MAP_FIXED : c_int = 0x0010;
28662866
pub const MAP_ANON : c_int = 0x0020;
28672867

2868-
pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
2868+
pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
28692869

28702870
pub const MCL_CURRENT : c_int = 0x0001;
28712871
pub const MCL_FUTURE : c_int = 0x0002;
@@ -4696,7 +4696,7 @@ pub mod consts {
46964696
pub const MAP_FIXED : c_int = 0x0010;
46974697
pub const MAP_ANON : c_int = 0x1000;
46984698

4699-
pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
4699+
pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
47004700

47014701
pub const MCL_CURRENT : c_int = 0x0001;
47024702
pub const MCL_FUTURE : c_int = 0x0002;

src/librand/distributions/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ mod tests {
361361
}
362362
#[test] #[should_panic]
363363
fn test_weighted_choice_weight_overflows() {
364-
let x = (-1) as usize / 2; // x + x + 2 is the overflow
364+
let x = (!0) as usize / 2; // x + x + 2 is the overflow
365365
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
366366
Weighted { weight: 1, item: 1 },
367367
Weighted { weight: x, item: 2 },

src/librustc/middle/const_eval.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use middle::astconv_util::ast_ty_to_prim_ty;
2323

2424
use syntax::ast::{self, Expr};
2525
use syntax::codemap::Span;
26+
use syntax::feature_gate;
2627
use syntax::parse::token::InternedString;
2728
use syntax::ptr::P;
2829
use syntax::{ast_map, ast_util, codemap};
@@ -395,7 +396,7 @@ pub fn const_int_checked_neg<'a>(
395396
pub fn const_uint_checked_neg<'a>(
396397
a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
397398
// This always succeeds, and by definition, returns `(!a)+1`.
398-
Ok(const_uint(-a))
399+
Ok(const_uint((!a).wrapping_add(1)))
399400
}
400401

401402
macro_rules! overflow_checking_body {
@@ -594,7 +595,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
594595
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
595596
const_float(f) => const_float(-f),
596597
const_int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
597-
const_uint(n) => try!(const_uint_checked_neg(n, e, expr_uint_type)),
598+
const_uint(i) => {
599+
if !tcx.sess.features.borrow().negate_unsigned {
600+
feature_gate::emit_feature_err(
601+
&tcx.sess.parse_sess.span_diagnostic,
602+
"negate_unsigned",
603+
e.span,
604+
"unary negation of unsigned integers may be removed in the future");
605+
}
606+
try!(const_uint_checked_neg(i, e, expr_uint_type))
607+
}
598608
const_str(_) => signal!(e, NegateOnString),
599609
const_bool(_) => signal!(e, NegateOnBoolean),
600610
const_binary(_) => signal!(e, NegateOnBinary),

src/librustc_lint/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub struct TypeLimits {
116116
impl TypeLimits {
117117
pub fn new() -> TypeLimits {
118118
TypeLimits {
119-
negated_expr_id: -1,
119+
negated_expr_id: !0,
120120
}
121121
}
122122
}

src/librustc_trans/trans/adt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
830830
let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
831831
assert!(bits <= 64);
832832
let bits = bits as usize;
833-
let mask = (-1u64 >> (64 - bits)) as Disr;
833+
let mask = (!0u64 >> (64 - bits)) as Disr;
834834
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
835835
// However, that is fine here (it would still represent the full range),
836836
if (max.wrapping_add(1)) & mask == min & mask {

src/librustc_trans/trans/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
868868
_ => unreachable!(),
869869
};
870870
let minus_one = ICmp(bcx, llvm::IntEQ, rhs,
871-
C_integral(llty, -1, false), debug_loc);
871+
C_integral(llty, !0, false), debug_loc);
872872
with_cond(bcx, minus_one, |bcx| {
873873
let is_min = ICmp(bcx, llvm::IntEQ, lhs,
874874
C_integral(llty, min, true), debug_loc);
@@ -1388,7 +1388,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
13881388
common::validate_substs(param_substs);
13891389

13901390
debug!("new_fn_ctxt(path={}, id={}, param_substs={})",
1391-
if id == -1 {
1391+
if id == !0 {
13921392
"".to_string()
13931393
} else {
13941394
ccx.tcx().map.path_to_string(id).to_string()

src/librustc_trans/trans/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
459459
CrateContext {
460460
shared: shared,
461461
local: self,
462-
index: -1 as usize,
462+
index: !0 as usize,
463463
}
464464
}
465465
}

src/librustc_typeck/check/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ use syntax::attr::AttrMetaMethods;
120120
use syntax::ast::{self, DefId, Visibility};
121121
use syntax::ast_util::{self, local_def};
122122
use syntax::codemap::{self, Span};
123+
use syntax::feature_gate;
123124
use syntax::owned_slice::OwnedSlice;
124125
use syntax::parse::token;
125126
use syntax::print::pprust;
@@ -3258,6 +3259,15 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
32583259
tcx.lang_items.neg_trait(),
32593260
expr, &**oprnd, oprnd_t, unop);
32603261
}
3262+
if let ty::ty_uint(_) = oprnd_t.sty {
3263+
if !tcx.sess.features.borrow().negate_unsigned {
3264+
feature_gate::emit_feature_err(
3265+
&tcx.sess.parse_sess.span_diagnostic,
3266+
"negate_unsigned",
3267+
expr.span,
3268+
"unary negation of unsigned integers may be removed in the future");
3269+
}
3270+
}
32613271
}
32623272
}
32633273
}

src/libstd/fs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ mod tests {
946946
let mut read_stream = check!(File::open(filename));
947947
let mut read_buf = [0; 1028];
948948
let read_str = match check!(read_stream.read(&mut read_buf)) {
949-
-1|0 => panic!("shouldn't happen"),
949+
0 => panic!("shouldn't happen"),
950950
n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
951951
};
952952
assert_eq!(read_str, message);

src/libstd/old_io/fs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ mod test {
970970
let mut read_stream = File::open_mode(filename, Open, Read);
971971
let mut read_buf = [0; 1028];
972972
let read_str = match check!(read_stream.read(&mut read_buf)) {
973-
-1|0 => panic!("shouldn't happen"),
973+
0 => panic!("shouldn't happen"),
974974
n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
975975
};
976976
assert_eq!(read_str, message);

src/libstd/rt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
116116
use libc;
117117
use libc::funcs::posix01::signal::signal;
118118
unsafe {
119-
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
119+
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
120120
}
121121
}
122122
ignore_sigpipe();

src/libsyntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ pub const CRATE_NODE_ID: NodeId = 0;
388388
/// When parsing and doing expansions, we initially give all AST nodes this AST
389389
/// node value. Then later, in the renumber pass, we renumber them to have
390390
/// small, positive ids.
391-
pub const DUMMY_NODE_ID: NodeId = -1;
391+
pub const DUMMY_NODE_ID: NodeId = !0;
392392

393393
/// The AST represents all type param bounds as types.
394394
/// typeck::collect::compute_bounds matches these against

src/libsyntax/codemap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,9 @@ pub struct ExpnInfo {
278278
#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)]
279279
pub struct ExpnId(u32);
280280

281-
pub const NO_EXPANSION: ExpnId = ExpnId(-1);
281+
pub const NO_EXPANSION: ExpnId = ExpnId(!0);
282282
// For code appearing from the command line
283-
pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(-2);
283+
pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
284284

285285
impl ExpnId {
286286
pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {

0 commit comments

Comments
 (0)