diff options
| author | Florian Hahn <flo@fhahn.com> | 2013-10-27 19:59:58 +0100 |
|---|---|---|
| committer | Florian Hahn <flo@fhahn.com> | 2013-11-12 19:36:46 +0100 |
| commit | 20627c7430afd700cf0b462c372d9086c7c51f0a (patch) | |
| tree | 54ea2326a4face74ecc600b8c90eb079c05183a0 | |
| parent | be09626148fbc02a7949dfa6143c5923d764beba (diff) | |
| download | rust-20627c7430afd700cf0b462c372d9086c7c51f0a.tar.gz rust-20627c7430afd700cf0b462c372d9086c7c51f0a.zip | |
Check inferred integer literals for overflows, closes #4220
| -rw-r--r-- | doc/po/ja/tutorial-tasks.md.po | 2 | ||||
| -rw-r--r-- | doc/po/tutorial-tasks.md.pot | 2 | ||||
| -rw-r--r-- | doc/tutorial-tasks.md | 2 | ||||
| -rw-r--r-- | src/librustc/middle/lint.rs | 70 | ||||
| -rw-r--r-- | src/test/compile-fail/lint-type-limits.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/lint-type-overflow.rs | 50 | ||||
| -rw-r--r-- | src/test/compile-fail/oversized-literal.rs | 4 |
7 files changed, 126 insertions, 6 deletions
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 4983a5af3e5..ef78484c151 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/lint.rs b/src/librustc/middle/lint.rs index 21a9b1904dd..497c9f166a4 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -72,6 +72,7 @@ pub enum lint { non_uppercase_statics, non_uppercase_pattern_statics, type_limits, + type_overflow, unused_unsafe, managed_heap_memory, @@ -219,6 +220,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, @@ -321,6 +330,9 @@ struct Context { // 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 Context { @@ -507,7 +519,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"); + } + }, + + _ => () + }; + }, _ => () }; @@ -1078,11 +1131,25 @@ impl Visitor<()> for Context { } 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, ()); @@ -1139,6 +1206,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: &ast::Crate) { cur: SmallIntMap::new(), tcx: tcx, 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 <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. +// + +#[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 |
