Skip to content

Gate unsigned unary negate #23945

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 2, 2015
2 changes: 1 addition & 1 deletion src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,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 {
Expand Down
4 changes: 2 additions & 2 deletions src/libcollectionstest/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,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);
}
Expand All @@ -1097,7 +1097,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));
}

Expand Down
2 changes: 1 addition & 1 deletion src/libcore/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,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 {
Expand Down
52 changes: 49 additions & 3 deletions src/libcore/num/wrapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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 {
Expand Down
24 changes: 20 additions & 4 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 `!`.
///
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,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
Expand Down
16 changes: 8 additions & 8 deletions src/libcoretest/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
4 changes: 2 additions & 2 deletions src/liblibc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/librand/distributions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
14 changes: 12 additions & 2 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub struct TypeLimits {
impl TypeLimits {
pub fn new() -> TypeLimits {
TypeLimits {
negated_expr_id: -1,
negated_expr_id: !0,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
CrateContext {
shared: shared,
local: self,
index: -1 as usize,
index: !0 as usize,
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/old_io/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,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();
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading