From bac3eec67c367718c05585b72974c58a66f6abd0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 11 Jan 2016 12:31:46 +0100 Subject: [PATCH] [breaking-change] remove negate_unsigned feature gate --- src/librustc_lint/lib.rs | 2 + src/librustc_lint/types.rs | 84 +++++++++------ src/libsyntax/feature_gate.rs | 5 +- src/test/compile-fail/const-eval-overflow.rs | 9 +- src/test/compile-fail/const-eval-overflow0.rs | 100 ++++++++++++++++++ .../compile-fail/enum-discrim-too-small.rs | 1 - .../feature-gate-negate-unsigned.rs | 18 ++-- src/test/compile-fail/lint-type-limits.rs | 2 - src/test/run-pass/bitwise.rs | 6 +- src/test/run-pass/intrinsics-integer.rs | 18 ++-- .../run-pass/unary-minus-suffix-inference.rs | 24 ----- 11 files changed, 179 insertions(+), 90 deletions(-) create mode 100644 src/test/compile-fail/const-eval-overflow0.rs diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index f2e75960406f1..a2a5f846f3b51 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -38,6 +38,7 @@ #![feature(staged_api)] #![feature(str_char)] +#[macro_use] extern crate syntax; #[macro_use] extern crate rustc; @@ -153,4 +154,5 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { 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"); } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a1d029025b2fa..891c1aebcdf30 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -8,6 +8,8 @@ // 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; @@ -24,13 +26,39 @@ use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; 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 = -Wrapping(1); +let Wrapping(x) = x; +let y: usize = 1.wrapping_neg(); +assert_eq!(x, y); +``` + +"## +} + declare_lint! { UNUSED_COMPARISONS, Warn, @@ -73,30 +101,24 @@ impl LateLintPass for TypeLimits { 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; @@ -322,15 +344,11 @@ impl LateLintPass for TypeLimits { } } - 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(); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c281571305b8b..3054c307f36d9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -170,7 +170,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status ("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. @@ -548,7 +548,6 @@ pub struct Features { 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, /// #![feature] attrs for non-language (library) features @@ -585,7 +584,6 @@ impl 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, @@ -1174,7 +1172,6 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, 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"), diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index daa60955ad88d..2a2fc2ef080db 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -9,7 +9,6 @@ // 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 @@ -65,7 +64,7 @@ const VALS_I64: (i64, i64, i64, i64) = ); 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, @@ -75,7 +74,7 @@ const VALS_U8: (u8, u8, u8, u8) = ); 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, @@ -85,7 +84,7 @@ const VALS_U16: (u16, u16, u16, u16) = ); 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, @@ -95,7 +94,7 @@ const VALS_U32: (u32, u32, u32, u32) = ); 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, diff --git a/src/test/compile-fail/const-eval-overflow0.rs b/src/test/compile-fail/const-eval-overflow0.rs new file mode 100644 index 0000000000000..7db7de9cee30c --- /dev/null +++ b/src/test/compile-fail/const-eval-overflow0.rs @@ -0,0 +1,100 @@ +// 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 or the MIT license +// , 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(x: T) { + println!("{:?}", x); +} diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs index cdf7d026d5eeb..84a27a3820069 100644 --- a/src/test/compile-fail/enum-discrim-too-small.rs +++ b/src/test/compile-fail/enum-discrim-too-small.rs @@ -8,7 +8,6 @@ // 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 { diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs index b1c73fab4ffa6..15cc17b19db33 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs @@ -8,8 +8,7 @@ // 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 { @@ -18,21 +17,26 @@ 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 } diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index 839d50ae63f90..0b414ad73db6f 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -8,9 +8,7 @@ // 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/bitwise.rs b/src/test/run-pass/bitwise.rs index a9f19c12b0278..ac24ed8d91604 100644 --- a/src/test/run-pass/bitwise.rs +++ b/src/test/run-pass/bitwise.rs @@ -8,16 +8,14 @@ // 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() { diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 170a6c95aa8a8..759dc515456de 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(negate_unsigned)] #![feature(intrinsics)] mod rusti { @@ -45,10 +43,10 @@ pub fn main() { 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); @@ -70,10 +68,10 @@ pub fn main() { 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); diff --git a/src/test/run-pass/unary-minus-suffix-inference.rs b/src/test/run-pass/unary-minus-suffix-inference.rs index fdb70fe248eff..cff260c3ba63e 100644 --- a/src/test/run-pass/unary-minus-suffix-inference.rs +++ b/src/test/run-pass/unary-minus-suffix-inference.rs @@ -8,8 +8,6 @@ // 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; @@ -30,26 +28,4 @@ pub fn main() { 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); }