Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly ban the negation of unsigned integers in type-checking. #38776

Merged
merged 1 commit into from
Jan 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.