Skip to content

Commit fbdadcb

Browse files
committed
Properly ban the negation of unsigned integers in type-checking.
1 parent df61658 commit fbdadcb

File tree

7 files changed

+28
-203
lines changed

7 files changed

+28
-203
lines changed

src/librustc_lint/types.rs

-51
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,6 @@ use rustc::hir;
3535

3636
use rustc_i128::{i128, u128};
3737

38-
register_long_diagnostics! {
39-
E0519: r##"
40-
It is not allowed to negate an unsigned integer.
41-
You can negate a signed integer and cast it to an
42-
unsigned integer or use the `!` operator.
43-
44-
```
45-
let x: usize = -1isize as usize;
46-
let y: usize = !0;
47-
assert_eq!(x, y);
48-
```
49-
50-
Alternatively you can use the `Wrapping` newtype
51-
or the `wrapping_neg` operation that all
52-
integral types support:
53-
54-
```
55-
use std::num::Wrapping;
56-
let x: Wrapping<usize> = -Wrapping(1);
57-
let Wrapping(x) = x;
58-
let y: usize = 1.wrapping_neg();
59-
assert_eq!(x, y);
60-
```
61-
"##
62-
}
63-
6438
declare_lint! {
6539
UNUSED_COMPARISONS,
6640
Warn,
@@ -109,24 +83,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
10983
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
11084
match e.node {
11185
hir::ExprUnary(hir::UnNeg, ref expr) => {
112-
if let hir::ExprLit(ref lit) = expr.node {
113-
match lit.node {
114-
ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
115-
forbid_unsigned_negation(cx, e.span);
116-
}
117-
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
118-
if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty {
119-
forbid_unsigned_negation(cx, e.span);
120-
}
121-
}
122-
_ => (),
123-
}
124-
} else {
125-
let t = cx.tcx.tables().node_id_to_type(expr.id);
126-
if let ty::TyUint(_) = t.sty {
127-
forbid_unsigned_negation(cx, e.span);
128-
}
129-
}
13086
// propagate negation, if the negation itself isn't negated
13187
if self.negated_expr_id != e.id {
13288
self.negated_expr_id = expr.id;
@@ -369,13 +325,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
369325
_ => false,
370326
}
371327
}
372-
373-
fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
374-
cx.sess()
375-
.struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
376-
.span_help(span, "use a cast or the `!` operator")
377-
.emit();
378-
}
379328
}
380329
}
381330

src/librustc_typeck/check/mod.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -3552,19 +3552,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
35523552
hir::UnNot => {
35533553
oprnd_t = self.structurally_resolved_type(oprnd.span,
35543554
oprnd_t);
3555+
let result = self.check_user_unop("!", "not",
3556+
tcx.lang_items.not_trait(),
3557+
expr, &oprnd, oprnd_t, unop);
3558+
// If it's builtin, we can reuse the type, this helps inference.
35553559
if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
3556-
oprnd_t = self.check_user_unop("!", "not",
3557-
tcx.lang_items.not_trait(),
3558-
expr, &oprnd, oprnd_t, unop);
3560+
oprnd_t = result;
35593561
}
35603562
}
35613563
hir::UnNeg => {
35623564
oprnd_t = self.structurally_resolved_type(oprnd.span,
35633565
oprnd_t);
3566+
let result = self.check_user_unop("-", "neg",
3567+
tcx.lang_items.neg_trait(),
3568+
expr, &oprnd, oprnd_t, unop);
3569+
// If it's builtin, we can reuse the type, this helps inference.
35643570
if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
3565-
oprnd_t = self.check_user_unop("-", "neg",
3566-
tcx.lang_items.neg_trait(),
3567-
expr, &oprnd, oprnd_t, unop);
3571+
oprnd_t = result;
35683572
}
35693573
}
35703574
}

src/librustc_typeck/check/writeback.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
123123
// as potentially overloaded. But then, during writeback, if
124124
// we observe that something like `a+b` is (known to be)
125125
// operating on scalars, we clear the overload.
126-
fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
126+
fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) {
127127
match e.node {
128+
hir::ExprUnary(hir::UnNeg, ref inner) |
129+
hir::ExprUnary(hir::UnNot, ref inner) => {
130+
let inner_ty = self.fcx.node_ty(inner.id);
131+
let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
132+
133+
if inner_ty.is_scalar() {
134+
self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
135+
}
136+
}
128137
hir::ExprBinary(ref op, ref lhs, ref rhs) |
129138
hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
130139
let lhs_ty = self.fcx.node_ty(lhs.id);
@@ -185,7 +194,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
185194
return;
186195
}
187196

188-
self.fix_scalar_binary_expr(e);
197+
self.fix_scalar_builtin_expr(e);
189198

190199
self.visit_node_id(ResolvingExpr(e.span), e.id);
191200
self.visit_method_map_entry(ResolvingExpr(e.span),

src/test/compile-fail/const-eval-overflow0.rs

-100
This file was deleted.

src/test/compile-fail/feature-gate-negate-unsigned.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,13 @@ impl std::ops::Neg for S {
1616
fn neg(self) -> u32 { 0 }
1717
}
1818

19-
// FIXME(eddyb) move this back to a `-1` literal when
20-
// MIR building stops eagerly erroring in that case.
21-
const _MAX: usize = -(2 - 1);
22-
//~^ WARN unary negation of unsigned integer
23-
//~| ERROR unary negation of unsigned integer
24-
//~| HELP use a cast or the `!` operator
25-
2619
fn main() {
20+
let _max: usize = -1;
21+
//~^ ERROR cannot apply unary operator `-` to type `usize`
22+
2723
let x = 5u8;
28-
let _y = -x; //~ ERROR unary negation of unsigned integer
29-
//~^ HELP use a cast or the `!` operator
24+
let _y = -x;
25+
//~^ ERROR cannot apply unary operator `-` to type `u8`
26+
3027
-S; // should not trigger the gate; issue 26840
3128
}

src/test/compile-fail/feature-gate-negate-unsigned0.rs

-34
This file was deleted.

0 commit comments

Comments
 (0)