Skip to content

Commit

Permalink
Properly ban the negation of unsigned integers in type-checking.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Jan 3, 2017
1 parent df61658 commit fbdadcb
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 203 deletions.
51 changes: 0 additions & 51 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}
}

Expand Down
16 changes: 10 additions & 6 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand Down
13 changes: 11 additions & 2 deletions src/librustc_typeck/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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),
Expand Down
100 changes: 0 additions & 100 deletions src/test/compile-fail/const-eval-overflow0.rs

This file was deleted.

15 changes: 6 additions & 9 deletions src/test/compile-fail/feature-gate-negate-unsigned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
34 changes: 0 additions & 34 deletions src/test/compile-fail/feature-gate-negate-unsigned0.rs

This file was deleted.

0 comments on commit fbdadcb

Please sign in to comment.