diff --git a/doc/po/ja/tutorial-tasks.md.po b/doc/po/ja/tutorial-tasks.md.po index e0cf7467db9..9cea63f0d0b 100644 --- a/doc/po/ja/tutorial-tasks.md.po +++ b/doc/po/ja/tutorial-tasks.md.po @@ -529,7 +529,7 @@ msgid "" "The basic example below illustrates this.\n" "~~~\n" "# fn make_a_sandwich() {};\n" -"fn fib(n: uint) -> uint {\n" +"fn fib(n: u64) -> u64 {\n" " // lengthy computation returning an uint\n" " 12586269025\n" "}\n" diff --git a/doc/po/tutorial-tasks.md.pot b/doc/po/tutorial-tasks.md.pot index f4dde0cb4e3..483cde9d7d0 100644 --- a/doc/po/tutorial-tasks.md.pot +++ b/doc/po/tutorial-tasks.md.pot @@ -529,7 +529,7 @@ msgid "" "The basic example below illustrates this.\n" "~~~\n" "# fn make_a_sandwich() {};\n" -"fn fib(n: uint) -> uint {\n" +"fn fib(n: u64) -> u64 {\n" " // lengthy computation returning an uint\n" " 12586269025\n" "}\n" diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 93c2b124fa5..adde4ab17e6 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -273,7 +273,7 @@ later. The basic example below illustrates this. ~~~ # fn make_a_sandwich() {}; -fn fib(n: uint) -> uint { +fn fib(n: u64) -> u64 { // lengthy computation returning an uint 12586269025 } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index d12808c3a4d..5f84f505b5c 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -199,21 +199,6 @@ pub fn check_expr(v: &mut CheckCrateVisitor, } } } - match e.node { - ExprLit(@codemap::Spanned {node: lit_int(v, t), _}) => { - if (v as u64) > ast_util::int_ty_max( - if t == ty_i { sess.targ_cfg.int_type } else { t }) { - sess.span_err(e.span, "literal out of range for its type"); - } - } - ExprLit(@codemap::Spanned {node: lit_uint(v, t), _}) => { - if v > ast_util::uint_ty_max( - if t == ty_u { sess.targ_cfg.uint_type } else { t }) { - sess.span_err(e.span, "literal out of range for its type"); - } - } - _ => () - } visit::walk_expr(v, e, is_const); } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 7890c1a6b5a..bc6cc00b786 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -73,6 +73,7 @@ pub enum lint { non_uppercase_statics, non_uppercase_pattern_statics, type_limits, + type_overflow, unused_unsafe, managed_heap_memory, @@ -220,6 +221,14 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ default: warn }), + ("type_overflow", + LintSpec { + lint: type_overflow, + desc: "literal out of range for its type", + default: warn + }), + + ("unused_unsafe", LintSpec { lint: unused_unsafe, @@ -329,6 +338,9 @@ struct Context<'self> { // levels, this stack keeps track of the previous lint levels of whatever // was modified. lint_stack: ~[(lint, level, LintSource)], + + // id of the last visited negated expression + negated_expr_id: ast::NodeId } impl<'self> Context<'self> { @@ -522,7 +534,48 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) { cx.span_lint(type_limits, e.span, "comparison is useless due to type limits"); } - } + }, + ast::ExprLit(lit) => { + match ty::get(ty::expr_ty(cx.tcx, e)).sty { + ty::ty_int(t) => { + let int_type = if t == ast::ty_i { + cx.tcx.sess.targ_cfg.int_type + } else { t }; + let (min, max) = int_ty_range(int_type); + let mut lit_val: i64 = match lit.node { + ast::lit_int(v, _) => v, + ast::lit_uint(v, _) => v as i64, + ast::lit_int_unsuffixed(v) => v, + _ => fail!() + }; + if cx.negated_expr_id == e.id { + lit_val *= -1; + } + if lit_val < min || lit_val > max { + cx.span_lint(type_overflow, e.span, + "literal out of range for its type"); + } + }, + ty::ty_uint(t) => { + let uint_type = if t == ast::ty_u { + cx.tcx.sess.targ_cfg.uint_type + } else { t }; + let (min, max) = uint_ty_range(uint_type); + let lit_val: u64 = match lit.node { + ast::lit_int(v, _) => v as u64, + ast::lit_uint(v, _) => v, + ast::lit_int_unsuffixed(v) => v as u64, + _ => fail!() + }; + if lit_val < min || lit_val > max { + cx.span_lint(type_overflow, e.span, + "literal out of range for its type"); + } + }, + + _ => () + }; + }, _ => () }; @@ -1052,11 +1105,25 @@ impl<'self> Visitor<()> for Context<'self> { } fn visit_expr(&mut self, e: @ast::Expr, _: ()) { + match e.node { + ast::ExprUnary(_, ast::UnNeg, expr) => { + // propagate negation, if the negation itself isn't negated + if self.negated_expr_id != e.id { + self.negated_expr_id = expr.id; + } + }, + ast::ExprParen(expr) => if self.negated_expr_id == e.id { + self.negated_expr_id = expr.id + }, + _ => () + }; + check_while_true_expr(self, e); check_stability(self, e); check_unused_unsafe(self, e); check_unnecessary_allocation(self, e); check_heap_expr(self, e); + check_type_limits(self, e); visit::walk_expr(self, e, ()); @@ -1150,6 +1217,7 @@ pub fn check_crate(tcx: ty::ctxt, cur_struct_def_id: -1, is_doc_hidden: false, lint_stack: ~[], + negated_expr_id: -1 }; // Install default lint levels, followed by the command line levels, and diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index 2eb794fd1c2..08714e3a044 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -24,11 +24,13 @@ fn bar() -> i8 { fn baz() -> bool { 128 > bar() //~ ERROR comparison is useless due to type limits + //~^ WARNING literal out of range for its type } fn qux() { let mut i = 1i8; while 200 != i { //~ ERROR comparison is useless due to type limits + //~^ WARNING literal out of range for its type i += 1; } } diff --git a/src/test/compile-fail/lint-type-overflow.rs b/src/test/compile-fail/lint-type-overflow.rs new file mode 100644 index 00000000000..27cd2bae125 --- /dev/null +++ b/src/test/compile-fail/lint-type-overflow.rs @@ -0,0 +1,50 @@ +// Copyright 2013 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. +// + +#[deny(type_overflow)]; + +fn test(x: i8) { + println!("x {}", x); +} + +#[allow(unused_variable)] +fn main() { + let x1: u8 = 255; // should be OK + let x1: u8 = 256; //~ error: literal out of range for its type + + let x1 = 255_u8; // should be OK + let x1 = 256_u8; //~ error: literal out of range for its type + + let x2: i8 = -128; // should be OK + let x1: i8 = 128; //~ error: literal out of range for its type + let x2: i8 = --128; //~ error: literal out of range for its type + + let x3: i8 = -129; //~ error: literal out of range for its type + let x3: i8 = -(129); //~ error: literal out of range for its type + let x3: i8 = -{129}; //~ error: literal out of range for its type + + test(1000); //~ error: literal out of range for its type + + let x = 128_i8; //~ error: literal out of range for its type + let x = 127_i8; + let x = -128_i8; + let x = -(128_i8); + let x = -129_i8; //~ error: literal out of range for its type + + let x: i32 = 2147483647; // should be OK + let x = 2147483647_i32; // should be OK + let x: i32 = 2147483648; //~ error: literal out of range for its type + let x = 2147483648_i32; //~ error: literal out of range for its type + let x: i32 = -2147483648; // should be OK + let x = -2147483648_i32; // should be OK + let x: i32 = -2147483649; //~ error: literal out of range for its type + let x = -2147483649_i32; //~ error: literal out of range for its type +} diff --git a/src/test/compile-fail/oversized-literal.rs b/src/test/compile-fail/oversized-literal.rs index 2e4ba8855bd..1c4316672f3 100644 --- a/src/test/compile-fail/oversized-literal.rs +++ b/src/test/compile-fail/oversized-literal.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:literal out of range +// compile-flags: -D type-overflow -fn main() { info!("{}", 300u8); } +fn main() { info!("{}", 300u8); } //~ error: literal out of range for its type