about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-04-01 18:36:21 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-04-01 18:36:21 -0700
commit9edbf42a342ced7357fe5ec225975f214d872fbc (patch)
tree3ac2106c48eb2997f0795c8bcef20f921407636b /src
parent2e3b0c051dca9880bf66b5366dccd2e0bb424b99 (diff)
parentf86318d63c86568b312f39da20bea67e328c1fc5 (diff)
downloadrust-9edbf42a342ced7357fe5ec225975f214d872fbc.tar.gz
rust-9edbf42a342ced7357fe5ec225975f214d872fbc.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/libcollections/slice.rs2
-rw-r--r--src/libcollectionstest/slice.rs4
-rw-r--r--src/libcore/atomic.rs2
-rw-r--r--src/libcore/cell.rs2
-rw-r--r--src/libcore/num/mod.rs2
-rw-r--r--src/libcore/num/wrapping.rs52
-rw-r--r--src/libcore/ops.rs24
-rw-r--r--src/libcore/str/mod.rs2
-rw-r--r--src/libcoretest/fmt/num.rs16
-rw-r--r--src/liblibc/lib.rs4
-rw-r--r--src/librand/distributions/mod.rs2
-rw-r--r--src/librustc/middle/const_eval.rs14
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_trans/trans/adt.rs2
-rw-r--r--src/librustc_trans/trans/base.rs4
-rw-r--r--src/librustc_trans/trans/context.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/libstd/fs.rs2
-rw-r--r--src/libstd/old_io/fs.rs2
-rw-r--r--src/libstd/rt/mod.rs2
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/codemap.rs4
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/test/compile-fail/const-eval-overflow.rs3
-rw-r--r--src/test/compile-fail/enum-discrim-too-small.rs2
-rw-r--r--src/test/compile-fail/lint-exceeding-bitshifts.rs3
-rw-r--r--src/test/compile-fail/lint-type-limits.rs2
-rw-r--r--src/test/run-pass/big-literals.rs8
-rw-r--r--src/test/run-pass/bitwise.rs1
-rw-r--r--src/test/run-pass/intrinsics-integer.rs1
-rw-r--r--src/test/run-pass/issue-17074.rs8
32 files changed, 146 insertions, 48 deletions
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index d35173cbebf..ff923fb1906 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -1135,7 +1135,7 @@ impl Iterator for ElementSwaps {
     // #[inline]
     fn next(&mut self) -> Option<(usize, usize)> {
         fn new_pos_wrapping(i: usize, s: Direction) -> usize {
-            i.wrapping_add(match s { Pos => 1, Neg => -1 })
+            i.wrapping_add(match s { Pos => 1, Neg => !0 /* aka -1 */ })
         }
 
         fn new_pos(i: usize, s: Direction) -> usize {
diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs
index 9dc12aa5bd9..5b0aceb76d1 100644
--- a/src/libcollectionstest/slice.rs
+++ b/src/libcollectionstest/slice.rs
@@ -1089,7 +1089,7 @@ fn test_bytes_set_memory() {
 #[should_panic]
 fn test_overflow_does_not_cause_segfault() {
     let mut v = vec![];
-    v.reserve_exact(-1);
+    v.reserve_exact(!0);
     v.push(1);
     v.push(2);
 }
@@ -1098,7 +1098,7 @@ fn test_overflow_does_not_cause_segfault() {
 #[should_panic]
 fn test_overflow_does_not_cause_segfault_managed() {
     let mut v = vec![Rc::new(1)];
-    v.reserve_exact(-1);
+    v.reserve_exact(!0);
     v.push(Rc::new(2));
 }
 
diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs
index 8c396a4e7fb..d738ff947c4 100644
--- a/src/libcore/atomic.rs
+++ b/src/libcore/atomic.rs
@@ -161,7 +161,7 @@ pub const ATOMIC_USIZE_INIT: AtomicUsize =
         AtomicUsize { v: UnsafeCell { value: 0, } };
 
 // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
-const UINT_TRUE: usize = -1;
+const UINT_TRUE: usize = !0;
 
 impl AtomicBool {
     /// Creates a new `AtomicBool`.
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 906c87f3ffd..76e09eedbdf 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -287,7 +287,7 @@ pub enum BorrowState {
 // (will not outgrow its range since `usize` is the size of the address space)
 type BorrowFlag = usize;
 const UNUSED: BorrowFlag = 0;
-const WRITING: BorrowFlag = -1;
+const WRITING: BorrowFlag = !0;
 
 impl<T> RefCell<T> {
     /// Creates a new `RefCell` containing `value`.
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 4e458e993a0..09bd2ab379a 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -516,7 +516,7 @@ macro_rules! uint_impl {
             fn min_value() -> $T { 0 }
 
             #[inline]
-            fn max_value() -> $T { -1 }
+            fn max_value() -> $T { !0 }
 
             #[inline]
             fn count_ones(self) -> u32 {
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
index a78eed8ae5f..28276d0bf01 100644
--- a/src/libcore/num/wrapping.rs
+++ b/src/libcore/num/wrapping.rs
@@ -30,7 +30,7 @@ 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};
+use ::{i8,i16,i32,i64};
 
 #[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
 #[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
@@ -206,7 +206,7 @@ mod shift_max {
     pub const u64: u32 = i64;
 }
 
-macro_rules! overflowing_impl {
+macro_rules! signed_overflowing_impl {
     ($($t:ident)*) => ($(
         impl OverflowingOps for $t {
             #[inline(always)]
@@ -259,7 +259,53 @@ macro_rules! overflowing_impl {
     )*)
 }
 
-overflowing_impl! { u8 u16 u32 u64 i8 i16 i32 i64 }
+macro_rules! unsigned_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)
+                }
+            }
+
+            #[inline(always)]
+            fn overflowing_div(self, rhs: $t) -> ($t, bool) {
+                (self/rhs, false)
+            }
+            #[inline(always)]
+            fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
+                (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))
+            }
+        }
+    )*)
+}
+
+signed_overflowing_impl! { i8 i16 i32 i64 }
+unsigned_overflowing_impl! { u8 u16 u32 u64 }
 
 #[cfg(target_pointer_width = "64")]
 impl OverflowingOps for usize {
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 21af342b1bf..b39fb95d915 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -482,8 +482,10 @@ pub trait Neg {
     fn neg(self) -> Self::Output;
 }
 
-macro_rules! neg_impl {
-    ($($t:ty)*) => ($(
+
+
+macro_rules! neg_impl_core {
+    ($id:ident => $body:expr, $($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
         #[allow(unsigned_negation)]
         impl Neg for $t {
@@ -492,14 +494,28 @@ macro_rules! neg_impl {
 
             #[inline]
             #[stable(feature = "rust1", since = "1.0.0")]
-            fn neg(self) -> $t { -self }
+            fn neg(self) -> $t { let $id = self; $body }
         }
 
         forward_ref_unop! { impl Neg, neg for $t }
     )*)
 }
 
-neg_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+macro_rules! neg_impl_numeric {
+    ($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} }
+}
+
+macro_rules! neg_impl_unsigned {
+    ($($t:ty)*) => {
+        neg_impl_core!{ x => {
+            #[cfg(stage0)]
+            use ::num::wrapping::WrappingOps;
+            !x.wrapping_add(1)
+        }, $($t)*} }
+}
+
+// neg_impl_unsigned! { usize u8 u16 u32 u64 }
+neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 }
 
 /// The `Not` trait is used to specify the functionality of unary `!`.
 ///
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index f07c988c2b4..cad50155b0b 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -855,7 +855,7 @@ impl TwoWaySearcher {
     #[allow(dead_code)]
     #[allow(deprecated)]
     fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
-        let mut left: usize = -1; // Corresponds to i in the paper
+        let mut left: usize = !0; // 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
         let mut period = 1; // Corresponds to p in the paper
diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs
index 7db8db444ff..ba12ff306e9 100644
--- a/src/libcoretest/fmt/num.rs
+++ b/src/libcoretest/fmt/num.rs
@@ -125,14 +125,14 @@ fn test_format_int_flags() {
     assert!(format!("{:>8x}", 10) == "       a");
     assert!(format!("{:#08x}", 10) == "0x00000a");
     assert!(format!("{:08}", -10) == "-0000010");
-    assert!(format!("{:x}", -1u8) == "ff");
-    assert!(format!("{:X}", -1u8) == "FF");
-    assert!(format!("{:b}", -1u8) == "11111111");
-    assert!(format!("{:o}", -1u8) == "377");
-    assert!(format!("{:#x}", -1u8) == "0xff");
-    assert!(format!("{:#X}", -1u8) == "0xFF");
-    assert!(format!("{:#b}", -1u8) == "0b11111111");
-    assert!(format!("{:#o}", -1u8) == "0o377");
+    assert!(format!("{:x}", !0u8) == "ff");
+    assert!(format!("{:X}", !0u8) == "FF");
+    assert!(format!("{:b}", !0u8) == "11111111");
+    assert!(format!("{:o}", !0u8) == "377");
+    assert!(format!("{:#x}", !0u8) == "0xff");
+    assert!(format!("{:#X}", !0u8) == "0xFF");
+    assert!(format!("{:#b}", !0u8) == "0b11111111");
+    assert!(format!("{:#o}", !0u8) == "0o377");
 }
 
 #[test]
diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs
index b7162c4a177..bfc657f8784 100644
--- a/src/liblibc/lib.rs
+++ b/src/liblibc/lib.rs
@@ -2865,7 +2865,7 @@ pub mod consts {
             pub const MAP_FIXED : c_int = 0x0010;
             pub const MAP_ANON : c_int = 0x0020;
 
-            pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
 
             pub const MCL_CURRENT : c_int = 0x0001;
             pub const MCL_FUTURE : c_int = 0x0002;
@@ -4696,7 +4696,7 @@ pub mod consts {
             pub const MAP_FIXED : c_int = 0x0010;
             pub const MAP_ANON : c_int = 0x1000;
 
-            pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
 
             pub const MCL_CURRENT : c_int = 0x0001;
             pub const MCL_FUTURE : c_int = 0x0002;
diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs
index 62189e721e5..432081063c5 100644
--- a/src/librand/distributions/mod.rs
+++ b/src/librand/distributions/mod.rs
@@ -361,7 +361,7 @@ mod tests {
     }
     #[test] #[should_panic]
     fn test_weighted_choice_weight_overflows() {
-        let x = (-1) as usize / 2; // x + x + 2 is the overflow
+        let x = (!0) as usize / 2; // x + x + 2 is the overflow
         WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
                                   Weighted { weight: 1, item: 1 },
                                   Weighted { weight: x, item: 2 },
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index e3e5efc53c7..367bcbbe1d8 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -23,6 +23,7 @@ use middle::astconv_util::ast_ty_to_prim_ty;
 
 use syntax::ast::{self, Expr};
 use syntax::codemap::Span;
+use syntax::feature_gate;
 use syntax::parse::token::InternedString;
 use syntax::ptr::P;
 use syntax::{ast_map, ast_util, codemap};
@@ -395,7 +396,7 @@ pub fn const_int_checked_neg<'a>(
 pub fn const_uint_checked_neg<'a>(
     a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
     // This always succeeds, and by definition, returns `(!a)+1`.
-    Ok(const_uint(-a))
+    Ok(const_uint((!a).wrapping_add(1)))
 }
 
 macro_rules! overflow_checking_body {
@@ -594,7 +595,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
         match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
           const_float(f) => const_float(-f),
           const_int(n) =>  try!(const_int_checked_neg(n, e, expr_int_type)),
-          const_uint(n) => try!(const_uint_checked_neg(n, e, expr_uint_type)),
+          const_uint(i) => {
+              if !tcx.sess.features.borrow().negate_unsigned {
+                  feature_gate::emit_feature_err(
+                      &tcx.sess.parse_sess.span_diagnostic,
+                      "negate_unsigned",
+                      e.span,
+                      "unary negation of unsigned integers may be removed in the future");
+              }
+              try!(const_uint_checked_neg(i, e, expr_uint_type))
+          }
           const_str(_) => signal!(e, NegateOnString),
           const_bool(_) => signal!(e, NegateOnBoolean),
           const_binary(_) => signal!(e, NegateOnBinary),
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index e7443af3013..cc22f8ff809 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -116,7 +116,7 @@ pub struct TypeLimits {
 impl TypeLimits {
     pub fn new() -> TypeLimits {
         TypeLimits {
-            negated_expr_id: -1,
+            negated_expr_id: !0,
         }
     }
 }
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index e32d8e2b9cf..fd1fff308df 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -830,7 +830,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
     let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
     assert!(bits <= 64);
     let  bits = bits as usize;
-    let mask = (-1u64 >> (64 - bits)) as Disr;
+    let mask = (!0u64 >> (64 - bits)) as Disr;
     // For a (max) discr of -1, max will be `-1 as usize`, which overflows.
     // However, that is fine here (it would still represent the full range),
     if (max.wrapping_add(1)) & mask == min & mask {
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 20677ab93fc..51db1430ae2 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -868,7 +868,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
             _ => unreachable!(),
         };
         let minus_one = ICmp(bcx, llvm::IntEQ, rhs,
-                             C_integral(llty, -1, false), debug_loc);
+                             C_integral(llty, !0, false), debug_loc);
         with_cond(bcx, minus_one, |bcx| {
             let is_min = ICmp(bcx, llvm::IntEQ, lhs,
                               C_integral(llty, min, true), debug_loc);
@@ -1388,7 +1388,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     common::validate_substs(param_substs);
 
     debug!("new_fn_ctxt(path={}, id={}, param_substs={})",
-           if id == -1 {
+           if id == !0 {
                "".to_string()
            } else {
                ccx.tcx().map.path_to_string(id).to_string()
diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs
index 3542bcd081f..8919a386a45 100644
--- a/src/librustc_trans/trans/context.rs
+++ b/src/librustc_trans/trans/context.rs
@@ -459,7 +459,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
         CrateContext {
             shared: shared,
             local: self,
-            index: -1 as usize,
+            index: !0 as usize,
         }
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b9a0070f205..2d39fb6191d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -120,6 +120,7 @@ use syntax::attr::AttrMetaMethods;
 use syntax::ast::{self, DefId, Visibility};
 use syntax::ast_util::{self, local_def};
 use syntax::codemap::{self, Span};
+use syntax::feature_gate;
 use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token;
 use syntax::print::pprust;
@@ -3258,6 +3259,15 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                                                       tcx.lang_items.neg_trait(),
                                                       expr, &**oprnd, oprnd_t, unop);
                     }
+                    if let ty::ty_uint(_) = oprnd_t.sty {
+                        if !tcx.sess.features.borrow().negate_unsigned {
+                            feature_gate::emit_feature_err(
+                                &tcx.sess.parse_sess.span_diagnostic,
+                                "negate_unsigned",
+                                expr.span,
+                                "unary negation of unsigned integers may be removed in the future");
+                        }
+                    }
                 }
             }
         }
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 4f97ae8f69b..eabc51beb12 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -946,7 +946,7 @@ mod tests {
             let mut read_stream = check!(File::open(filename));
             let mut read_buf = [0; 1028];
             let read_str = match check!(read_stream.read(&mut read_buf)) {
-                -1|0 => panic!("shouldn't happen"),
+                0 => panic!("shouldn't happen"),
                 n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
             };
             assert_eq!(read_str, message);
diff --git a/src/libstd/old_io/fs.rs b/src/libstd/old_io/fs.rs
index bef6ea53e50..509daa46ef3 100644
--- a/src/libstd/old_io/fs.rs
+++ b/src/libstd/old_io/fs.rs
@@ -970,7 +970,7 @@ mod test {
             let mut read_stream = File::open_mode(filename, Open, Read);
             let mut read_buf = [0; 1028];
             let read_str = match check!(read_stream.read(&mut read_buf)) {
-                -1|0 => panic!("shouldn't happen"),
+                0 => panic!("shouldn't happen"),
                 n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
             };
             assert_eq!(read_str, message);
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 632d9647212..0d26206f26b 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -116,7 +116,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
             use libc;
             use libc::funcs::posix01::signal::signal;
             unsafe {
-                assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
+                assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
             }
         }
         ignore_sigpipe();
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ce1539c62f8..40390765dde 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -388,7 +388,7 @@ pub const CRATE_NODE_ID: NodeId = 0;
 /// When parsing and doing expansions, we initially give all AST nodes this AST
 /// node value. Then later, in the renumber pass, we renumber them to have
 /// small, positive ids.
-pub const DUMMY_NODE_ID: NodeId = -1;
+pub const DUMMY_NODE_ID: NodeId = !0;
 
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 6a00fff1860..c2f2c51ed2c 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -278,9 +278,9 @@ pub struct ExpnInfo {
 #[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)]
 pub struct ExpnId(u32);
 
-pub const NO_EXPANSION: ExpnId = ExpnId(-1);
+pub const NO_EXPANSION: ExpnId = ExpnId(!0);
 // For code appearing from the command line
-pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(-2);
+pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
 
 impl ExpnId {
     pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 4c01cecc67c..2aa405bf6df 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -152,6 +152,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
 
     // #23121. Array patterns have some hazards yet.
     ("slice_patterns", "1.0.0", Active),
+
+    // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
+    ("negate_unsigned", "1.0.0", Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -325,6 +328,7 @@ pub struct Features {
     pub allow_custom_derive: bool,
     pub simd_ffi: bool,
     pub unmarked_api: bool,
+    pub negate_unsigned: bool,
     /// spans of #![feature] attrs for stable language features. for error reporting
     pub declared_stable_lang_features: Vec<Span>,
     /// #![feature] attrs for non-language (library) features
@@ -346,6 +350,7 @@ impl Features {
             allow_custom_derive: false,
             simd_ffi: false,
             unmarked_api: false,
+            negate_unsigned: false,
             declared_stable_lang_features: Vec::new(),
             declared_lib_features: Vec::new()
         }
@@ -724,6 +729,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
         allow_custom_derive: cx.has_feature("custom_derive"),
         simd_ffi: cx.has_feature("simd_ffi"),
         unmarked_api: cx.has_feature("unmarked_api"),
+        negate_unsigned: cx.has_feature("negate_unsigned"),
         declared_stable_lang_features: accepted_features,
         declared_lib_features: unknown_features
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c2f323f98af..3e0c938649d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -3053,7 +3053,7 @@ mod test {
     #[test]
     fn test_signed_int_to_string() {
         let pos_int = ast::LitInt(42, ast::SignedIntLit(ast::TyI32, ast::Plus));
-        let neg_int = ast::LitInt((-42) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
+        let neg_int = ast::LitInt((!42 + 1) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
         assert_eq!(format!("-{}", lit_to_string(&codemap::dummy_spanned(pos_int))),
                    lit_to_string(&codemap::dummy_spanned(neg_int)));
     }
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
index f647c43e137..19b5f9b094c 100644
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ b/src/test/compile-fail/const-eval-overflow.rs
@@ -8,7 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(negate_unsigned)]
+
 #![allow(unused_imports)]
+#![feature(negate_unsigned)]
 
 // Note: the relevant lint pass here runs before some of the constant
 // evaluation below (e.g. that performed by trans and llvm), so if you
diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs
index 1d7794336a0..cdf7d026d5e 100644
--- a/src/test/compile-fail/enum-discrim-too-small.rs
+++ b/src/test/compile-fail/enum-discrim-too-small.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(negate_unsigned)]
+
 #[repr(u8)] //~ NOTE discriminant type specified here
 enum Eu8 {
     Au8 = 23,
diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs
index 171dedd5b2e..1f70828e411 100644
--- a/src/test/compile-fail/lint-exceeding-bitshifts.rs
+++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(negate_unsigned)]
 #![deny(exceeding_bitshifts)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
-#![feature(core)]
+#![feature(core, negate_unsigned)]
 
 fn main() {
       let n = 1u8 << 7;
diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs
index f36c726c875..798dc112b0a 100644
--- a/src/test/compile-fail/lint-type-limits.rs
+++ b/src/test/compile-fail/lint-type-limits.rs
@@ -8,7 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(negate_unsigned)]
 #![allow(dead_code)]
+#![feature(negate_unsigned)]
 
 // compile-flags: -D unused-comparisons
 fn main() { }
diff --git a/src/test/run-pass/big-literals.rs b/src/test/run-pass/big-literals.rs
index b73eac0c714..ab9d892ce2b 100644
--- a/src/test/run-pass/big-literals.rs
+++ b/src/test/run-pass/big-literals.rs
@@ -16,10 +16,10 @@
 #![deny(overflowing_literals)]
 
 pub fn main() {
-    assert_eq!(0xffffffff, (-1 as u32));
-    assert_eq!(4294967295, (-1 as u32));
-    assert_eq!(0xffffffffffffffff, (-1 as u64));
-    assert_eq!(18446744073709551615, (-1 as u64));
+    assert_eq!(0xffffffff, (!0 as u32));
+    assert_eq!(4294967295, (!0 as u32));
+    assert_eq!(0xffffffffffffffff, (!0 as u64));
+    assert_eq!(18446744073709551615, (!0 as u64));
 
     assert_eq!((-2147483648i32).wrapping_sub(1), 2147483647);
 }
diff --git a/src/test/run-pass/bitwise.rs b/src/test/run-pass/bitwise.rs
index d6117a04e35..a9f19c12b02 100644
--- a/src/test/run-pass/bitwise.rs
+++ b/src/test/run-pass/bitwise.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(negate_unsigned)]
 
 #[cfg(any(target_arch = "x86", target_arch = "arm"))]
 fn target() {
diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs
index a4661410ad6..15dbe796ef5 100644
--- a/src/test/run-pass/intrinsics-integer.rs
+++ b/src/test/run-pass/intrinsics-integer.rs
@@ -10,6 +10,7 @@
 
 // pretty-expanded FIXME #23616
 
+#![feature(negate_unsigned)]
 #![feature(intrinsics)]
 
 mod rusti {
diff --git a/src/test/run-pass/issue-17074.rs b/src/test/run-pass/issue-17074.rs
index 31f6a4209de..08c313ab0a4 100644
--- a/src/test/run-pass/issue-17074.rs
+++ b/src/test/run-pass/issue-17074.rs
@@ -10,10 +10,10 @@
 
 // pretty-expanded FIXME #23616
 
-static X2: u64 = -1 as u16 as u64;
-static Y2: u64 = -1 as u32 as u64;
-const X: u64 = -1 as u16 as u64;
-const Y: u64 = -1 as u32 as u64;
+static X2: u64 = !0 as u16 as u64;
+static Y2: u64 = !0 as u32 as u64;
+const X: u64 = !0 as u16 as u64;
+const Y: u64 = !0 as u32 as u64;
 
 fn main() {
     assert_eq!(match 1 {