Auto merge of #38776 - eddyb:unsigned-means-unsigned, r=pnkfelix
Properly ban the negation of unsigned integers in type-checking. Lint-time banning of unsigned negation appears to be vestigial from a time it was feature-gated. But now it always errors and we do have the ability to deref the checking of e.g. `-0`, through the trait obligation fulfillment context, which will only succeed/error when the `0` gets inferred to a specific type. The two removed tests are the main reason for finally cleaning this up, they need changing all the time when refactoring the HIR-based `rustc_const_eval` and/or `rustc_passes::consts`, as warnings pile up.
This commit is contained in:
commit
2f56207b12
@ -1 +1 @@
|
||||
Subproject commit 98589876259e19f13eab81b033ced95bbb6deca0
|
||||
Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc
|
@ -35,32 +35,6 @@ use rustc::hir;
|
||||
|
||||
use rustc_i128::{i128, u128};
|
||||
|
||||
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,
|
||||
@ -109,24 +83,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
|
||||
match e.node {
|
||||
hir::ExprUnary(hir::UnNeg, ref expr) => {
|
||||
if let hir::ExprLit(ref lit) = expr.node {
|
||||
match lit.node {
|
||||
ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
|
||||
forbid_unsigned_negation(cx, e.span);
|
||||
}
|
||||
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
|
||||
if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty {
|
||||
forbid_unsigned_negation(cx, e.span);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
let t = cx.tcx.tables().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;
|
||||
@ -369,13 +325,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3552,19 +3552,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
hir::UnNot => {
|
||||
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
||||
oprnd_t);
|
||||
let result = self.check_user_unop("!", "not",
|
||||
tcx.lang_items.not_trait(),
|
||||
expr, &oprnd, oprnd_t, unop);
|
||||
// If it's builtin, we can reuse the type, this helps inference.
|
||||
if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
|
||||
oprnd_t = self.check_user_unop("!", "not",
|
||||
tcx.lang_items.not_trait(),
|
||||
expr, &oprnd, oprnd_t, unop);
|
||||
oprnd_t = result;
|
||||
}
|
||||
}
|
||||
hir::UnNeg => {
|
||||
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
||||
oprnd_t);
|
||||
let result = self.check_user_unop("-", "neg",
|
||||
tcx.lang_items.neg_trait(),
|
||||
expr, &oprnd, oprnd_t, unop);
|
||||
// If it's builtin, we can reuse the type, this helps inference.
|
||||
if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
|
||||
oprnd_t = self.check_user_unop("-", "neg",
|
||||
tcx.lang_items.neg_trait(),
|
||||
expr, &oprnd, oprnd_t, unop);
|
||||
oprnd_t = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +123,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
// as potentially overloaded. But then, during writeback, if
|
||||
// we observe that something like `a+b` is (known to be)
|
||||
// operating on scalars, we clear the overload.
|
||||
fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
|
||||
fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) {
|
||||
match e.node {
|
||||
hir::ExprUnary(hir::UnNeg, ref inner) |
|
||||
hir::ExprUnary(hir::UnNot, ref inner) => {
|
||||
let inner_ty = self.fcx.node_ty(inner.id);
|
||||
let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
|
||||
|
||||
if inner_ty.is_scalar() {
|
||||
self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
|
||||
}
|
||||
}
|
||||
hir::ExprBinary(ref op, ref lhs, ref rhs) |
|
||||
hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
|
||||
let lhs_ty = self.fcx.node_ty(lhs.id);
|
||||
@ -185,7 +194,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.fix_scalar_binary_expr(e);
|
||||
self.fix_scalar_builtin_expr(e);
|
||||
|
||||
self.visit_node_id(ResolvingExpr(e.span), e.id);
|
||||
self.visit_method_map_entry(ResolvingExpr(e.span),
|
||||
|
@ -1,100 +0,0 @@
|
||||
// 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);
|
||||
}
|
@ -16,16 +16,13 @@ impl std::ops::Neg for S {
|
||||
fn neg(self) -> u32 { 0 }
|
||||
}
|
||||
|
||||
// FIXME(eddyb) move this back to a `-1` literal when
|
||||
// MIR building stops eagerly erroring in that case.
|
||||
const _MAX: usize = -(2 - 1);
|
||||
//~^ WARN unary negation of unsigned integer
|
||||
//~| ERROR unary negation of unsigned integer
|
||||
//~| HELP use a cast or the `!` operator
|
||||
|
||||
fn main() {
|
||||
let _max: usize = -1;
|
||||
//~^ ERROR cannot apply unary operator `-` to type `usize`
|
||||
|
||||
let x = 5u8;
|
||||
let _y = -x; //~ ERROR unary negation of unsigned integer
|
||||
//~^ HELP use a cast or the `!` operator
|
||||
let _y = -x;
|
||||
//~^ ERROR cannot apply unary operator `-` to type `u8`
|
||||
|
||||
-S; // should not trigger the gate; issue 26840
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// Test that negating unsigned integers doesn't compile
|
||||
|
||||
struct S;
|
||||
impl std::ops::Neg for S {
|
||||
type Output = u32;
|
||||
fn neg(self) -> u32 { 0 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = -1;
|
||||
//~^ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
let _b : u8 = a; // for infering variable a to u8.
|
||||
|
||||
let _d = -1u8;
|
||||
//~^ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
|
||||
for _ in -10..10u8 {}
|
||||
//~^ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
|
||||
-S; // should not trigger the gate; issue 26840
|
||||
}
|
Loading…
Reference in New Issue
Block a user