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:
bors 2017-01-05 11:06:10 +00:00
commit 2f56207b12
7 changed files with 28 additions and 203 deletions

@ -1 +1 @@
Subproject commit 98589876259e19f13eab81b033ced95bbb6deca0
Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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),

View File

@ -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);
}

View File

@ -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
}

View File

@ -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
}