From fbdadcbed4c9a04b909246a8145e3e722c63525b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 3 Jan 2017 21:48:17 +0200 Subject: [PATCH] Properly ban the negation of unsigned integers in type-checking. --- src/liblibc | 2 +- src/librustc_lint/types.rs | 51 --------- src/librustc_typeck/check/mod.rs | 16 +-- src/librustc_typeck/check/writeback.rs | 13 ++- src/test/compile-fail/const-eval-overflow0.rs | 100 ------------------ .../feature-gate-negate-unsigned.rs | 15 ++- .../feature-gate-negate-unsigned0.rs | 34 ------ 7 files changed, 28 insertions(+), 203 deletions(-) delete mode 100644 src/test/compile-fail/const-eval-overflow0.rs delete mode 100644 src/test/compile-fail/feature-gate-negate-unsigned0.rs diff --git a/src/liblibc b/src/liblibc index 98589876259..7d57bdcdbb5 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 98589876259e19f13eab81b033ced95bbb6deca0 +Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 95e955bd683..570365c407f 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -35,32 +35,6 @@ 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 = -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(); - } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 26dd53fecb2..ec1ca99c768 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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; } } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 9a2bfbf715a..6d32b7364f8 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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 index 7db7de9cee3..00000000000 --- a/src/test/compile-fail/const-eval-overflow0.rs +++ /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 or the MIT license -// , 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(x: T) { - println!("{:?}", x); -} diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs index 98cc2fc0c3e..599e31341f2 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs @@ -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 index 89ae1a09bd3..00000000000 --- a/src/test/compile-fail/feature-gate-negate-unsigned0.rs +++ /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 or the MIT license -// , 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 -}