#![feature(staged_api)]
#![feature(str_char)]
+#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
store.register_renamed("unknown_features", "unused_features");
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
+ store.register_removed("negate_unsigned", "cast a signed value instead");
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
+
use middle::{infer};
use middle::def_id::DefId;
use middle::subst::Substs;
use syntax::{abi, ast};
use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{self, Span};
-use syntax::feature_gate::{emit_feature_err, GateIssue};
use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
use rustc_front::hir;
use rustc_front::intravisit::{self, Visitor};
use rustc_front::util::is_shift_binop;
+register_long_diagnostics! {
+E0519: r##"
+It is not allowed to negate an unsigned integer.
+You can negate a signed integer and cast it to an
+unsigned integer or use the `!` operator.
+
+```
+let x: usize = -1isize as usize;
+let y: usize = !0;
+assert_eq!(x, y);
+```
+
+Alternatively you can use the `Wrapping` newtype
+or the `wrapping_neg` operation that all
+integral types support:
+
+```
+use std::num::Wrapping;
+let x: Wrapping<usize> = -Wrapping(1);
+let Wrapping(x) = x;
+let y: usize = 1.wrapping_neg();
+assert_eq!(x, y);
+```
+
+"##
+}
+
declare_lint! {
UNUSED_COMPARISONS,
Warn,
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
match e.node {
hir::ExprUnary(hir::UnNeg, ref expr) => {
- match expr.node {
- hir::ExprLit(ref lit) => {
- match lit.node {
- ast::LitInt(_, ast::UnsignedIntLit(_)) => {
- check_unsigned_negation_feature(cx, e.span);
- },
- ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
- if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
- check_unsigned_negation_feature(cx, e.span);
- }
- },
- _ => ()
- }
- },
- _ => {
- let t = cx.tcx.node_id_to_type(expr.id);
- match t.sty {
- ty::TyUint(_) => {
- check_unsigned_negation_feature(cx, e.span);
- },
- _ => ()
- }
+ if let hir::ExprLit(ref lit) = expr.node {
+ match lit.node {
+ ast::LitInt(_, ast::UnsignedIntLit(_)) => {
+ forbid_unsigned_negation(cx, e.span);
+ },
+ ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
+ if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
+ forbid_unsigned_negation(cx, e.span);
+ }
+ },
+ _ => ()
}
- };
+ } else {
+ let t = cx.tcx.node_id_to_type(expr.id);
+ if let ty::TyUint(_) = t.sty {
+ forbid_unsigned_negation(cx, e.span);
+ }
+ }
// propagate negation, if the negation itself isn't negated
if self.negated_expr_id != e.id {
self.negated_expr_id = expr.id;
}
}
- fn check_unsigned_negation_feature(cx: &LateContext, span: Span) {
- if !cx.sess().features.borrow().negate_unsigned {
- emit_feature_err(
- &cx.sess().parse_sess.span_diagnostic,
- "negate_unsigned",
- span,
- GateIssue::Language,
- "unary negation of unsigned integers may be removed in the future");
- }
+ fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
+ cx.sess()
+ .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
+ .span_help(span, "use a cast or the `!` operator")
+ .emit();
}
}
}
("slice_patterns", "1.0.0", Some(23121), Active),
// Allows use of unary negate on unsigned integers, e.g. -e for e: u8
- ("negate_unsigned", "1.0.0", Some(29645), Active),
+ ("negate_unsigned", "1.0.0", Some(29645), Removed),
// Allows the definition of associated constants in `trait` or `impl`
// blocks.
pub allow_pushpop_unsafe: 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
allow_pushpop_unsafe: false,
simd_ffi: false,
unmarked_api: false,
- negate_unsigned: false,
declared_stable_lang_features: Vec::new(),
declared_lib_features: Vec::new(),
const_fn: false,
allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
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,
const_fn: cx.has_feature("const_fn"),
// except according to those terms.
#![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
);
const VALS_U8: (u8, u8, u8, u8) =
- (-u8::MIN,
+ (-(u8::MIN as i8) as u8,
u8::MIN - 1,
//~^ ERROR attempted to sub with overflow
u8::MAX + 1,
);
const VALS_U16: (u16, u16, u16, u16) =
- (-u16::MIN,
+ (-(u16::MIN as i16) as u16,
u16::MIN - 1,
//~^ ERROR attempted to sub with overflow
u16::MAX + 1,
);
const VALS_U32: (u32, u32, u32, u32) =
- (-u32::MIN,
+ (-(u32::MIN as i32) as u32,
u32::MIN - 1,
//~^ ERROR attempted to sub with overflow
u32::MAX + 1,
);
const VALS_U64: (u64, u64, u64, u64) =
- (-u64::MIN,
+ (-(u64::MIN as i64) as u64,
u64::MIN - 1,
//~^ ERROR attempted to sub with overflow
u64::MAX + 1,
--- /dev/null
+// Copyright 2015 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(unused_imports)]
+
+// 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
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8, i8, i8, i8) =
+ (-i8::MIN,
+ i8::MIN - 1,
+ i8::MAX + 1,
+ i8::MIN * 2,
+ );
+
+const VALS_I16: (i16, i16, i16, i16) =
+ (-i16::MIN,
+ i16::MIN - 1,
+ i16::MAX + 1,
+ i16::MIN * 2,
+ );
+
+const VALS_I32: (i32, i32, i32, i32) =
+ (-i32::MIN,
+ i32::MIN - 1,
+ i32::MAX + 1,
+ i32::MIN * 2,
+ );
+
+const VALS_I64: (i64, i64, i64, i64) =
+ (-i64::MIN,
+ i64::MIN - 1,
+ i64::MAX + 1,
+ i64::MAX * 2,
+ );
+
+const VALS_U8: (u8, u8, u8, u8) =
+ (-u8::MIN,
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
+ u8::MIN - 1,
+ u8::MAX + 1,
+ u8::MAX * 2,
+ );
+
+const VALS_U16: (u16, u16, u16, u16) =
+ (-u16::MIN,
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
+ u16::MIN - 1,
+ u16::MAX + 1,
+ u16::MAX * 2,
+ );
+
+const VALS_U32: (u32, u32, u32, u32) =
+ (-u32::MIN,
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
+ u32::MIN - 1,
+ u32::MAX + 1,
+ u32::MAX * 2,
+ );
+
+const VALS_U64: (u64, u64, u64, u64) =
+ (-u64::MIN,
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
+ u64::MIN - 1,
+ u64::MAX + 1,
+ u64::MAX * 2,
+ );
+
+fn main() {
+ foo(VALS_I8);
+ foo(VALS_I16);
+ foo(VALS_I32);
+ foo(VALS_I64);
+
+ foo(VALS_U8);
+ foo(VALS_U16);
+ foo(VALS_U32);
+ foo(VALS_U64);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", x);
+}
// 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 {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that negating unsigned integers is gated by `negate_unsigned` feature
-// gate
+// Test that negating unsigned integers doesn't compile
struct S;
impl std::ops::Neg for S {
}
const _MAX: usize = -1;
-//~^ ERROR unary negation of unsigned integers may be removed in the future
+//~^ ERROR unary negation of unsigned integer
+//~| HELP use a cast or the `!` operator
fn main() {
let a = -1;
- //~^ ERROR unary negation of unsigned integers may be removed in the future
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
let _b : u8 = a; // for infering variable a to u8.
-a;
- //~^ ERROR unary negation of unsigned integers may be removed in the future
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
let _d = -1u8;
- //~^ ERROR unary negation of unsigned integers may be removed in the future
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
for _ in -10..10u8 {}
- //~^ ERROR unary negation of unsigned integers may be removed in the future
+ //~^ ERROR unary negation of unsigned integer
+ //~| HELP use a cast or the `!` operator
-S; // should not trigger the gate; issue 26840
}
// 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() { }
// 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() {
- assert_eq!(-1000 as usize >> 3_usize, 536870787_usize);
+ assert_eq!(-1000isize as usize >> 3_usize, 536870787_usize);
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
fn target() {
- assert_eq!(-1000 as usize >> 3_usize, 2305843009213693827_usize);
+ assert_eq!(-1000isize as usize >> 3_usize, 2305843009213693827_usize);
}
fn general() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(negate_unsigned)]
#![feature(intrinsics)]
mod rusti {
assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3);
assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3);
- assert_eq!(ctpop(-1u8), 8); assert_eq!(ctpop(-1i8), 8);
- assert_eq!(ctpop(-1u16), 16); assert_eq!(ctpop(-1i16), 16);
- assert_eq!(ctpop(-1u32), 32); assert_eq!(ctpop(-1i32), 32);
- assert_eq!(ctpop(-1u64), 64); assert_eq!(ctpop(-1i64), 64);
+ assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8);
+ assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16);
+ assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32);
+ assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64);
assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8);
assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16);
assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25);
assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57);
- assert_eq!(cttz(-1u8), 0); assert_eq!(cttz(-1i8), 0);
- assert_eq!(cttz(-1u16), 0); assert_eq!(cttz(-1i16), 0);
- assert_eq!(cttz(-1u32), 0); assert_eq!(cttz(-1i32), 0);
- assert_eq!(cttz(-1u64), 0); assert_eq!(cttz(-1i64), 0);
+ assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0);
+ assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0);
+ assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0);
+ assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0);
assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8);
assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(negate_unsigned)]
-
pub fn main() {
let a = 1;
let a_neg: i8 = -a;
let e = 1;
let e_neg: isize = -e;
println!("{}", e_neg);
-
- // intentional overflows
-
- let f = 1;
- let f_neg: u8 = -f;
- println!("{}", f_neg);
-
- let g = 1;
- let g_neg: u16 = -g;
- println!("{}", g_neg);
-
- let h = 1;
- let h_neg: u32 = -h;
- println!("{}", h_neg);
-
- let i = 1;
- let i_neg: u64 = -i;
- println!("{}", i_neg);
-
- let j = 1;
- let j_neg: usize = -j;
- println!("{}", j_neg);
}