]> git.lizzy.rs Git - rust.git/commitdiff
Properly ban the negation of unsigned integers in type-checking.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Tue, 3 Jan 2017 19:48:17 +0000 (21:48 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Tue, 3 Jan 2017 19:48:17 +0000 (21:48 +0200)
src/liblibc
src/librustc_lint/types.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/writeback.rs
src/test/compile-fail/const-eval-overflow0.rs [deleted file]
src/test/compile-fail/feature-gate-negate-unsigned.rs
src/test/compile-fail/feature-gate-negate-unsigned0.rs [deleted file]

index 98589876259e19f13eab81b033ced95bbb6deca0..7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 98589876259e19f13eab81b033ced95bbb6deca0
+Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc
index 95e955bd6833e85edf233bfd16d339b57c6b0815..570365c407f48b55b0e5f9ea6c7fd8d2dfb89c44 100644 (file)
 
 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 @@ fn is_comparison(binop: hir::BinOp) -> bool {
                 _ => 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();
-        }
     }
 }
 
index 26dd53fecb243e306626a2ecd57ca7a2bf5ebb74..ec1ca99c7687f3af9c00aae4053c5e483643b5d2 100644 (file)
@@ -3552,19 +3552,23 @@ fn check_expr_kind(&self,
                     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;
                         }
                     }
                 }
index 9a2bfbf715af9785bb6432e24c9264dd63d65459..6d32b7364f8ea36aff3b3fb2b366cb756e1b6d05 100644 (file)
@@ -123,8 +123,17 @@ fn write_ty_to_tcx(&self, node_id: ast::NodeId, ty: Ty<'gcx>) {
     // 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 @@ fn visit_expr(&mut self, e: &'gcx hir::Expr) {
             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),
diff --git a/src/test/compile-fail/const-eval-overflow0.rs b/src/test/compile-fail/const-eval-overflow0.rs
deleted file mode 100644 (file)
index 7db7de9..0000000
+++ /dev/null
@@ -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);
-}
index 98cc2fc0c3e0cf9ec22d2de7dde2b3c5d5e04163..599e31341f2332a69a6c84c31c804698df838120 100644 (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
 }
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
deleted file mode 100644 (file)
index 89ae1a0..0000000
+++ /dev/null
@@ -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
-}