Skip to content

Commit 20627c7

Browse files
committed
Check inferred integer literals for overflows, closes #4220
1 parent be09626 commit 20627c7

File tree

7 files changed

+126
-6
lines changed

7 files changed

+126
-6
lines changed

doc/po/ja/tutorial-tasks.md.po

+1-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ msgid ""
529529
"The basic example below illustrates this.\n"
530530
"~~~\n"
531531
"# fn make_a_sandwich() {};\n"
532-
"fn fib(n: uint) -> uint {\n"
532+
"fn fib(n: u64) -> u64 {\n"
533533
" // lengthy computation returning an uint\n"
534534
" 12586269025\n"
535535
"}\n"

doc/po/tutorial-tasks.md.pot

+1-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ msgid ""
529529
"The basic example below illustrates this.\n"
530530
"~~~\n"
531531
"# fn make_a_sandwich() {};\n"
532-
"fn fib(n: uint) -> uint {\n"
532+
"fn fib(n: u64) -> u64 {\n"
533533
" // lengthy computation returning an uint\n"
534534
" 12586269025\n"
535535
"}\n"

doc/tutorial-tasks.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ later.
273273
The basic example below illustrates this.
274274
~~~
275275
# fn make_a_sandwich() {};
276-
fn fib(n: uint) -> uint {
276+
fn fib(n: u64) -> u64 {
277277
// lengthy computation returning an uint
278278
12586269025
279279
}

src/librustc/middle/lint.rs

+69-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub enum lint {
7272
non_uppercase_statics,
7373
non_uppercase_pattern_statics,
7474
type_limits,
75+
type_overflow,
7576
unused_unsafe,
7677

7778
managed_heap_memory,
@@ -219,6 +220,14 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
219220
default: warn
220221
}),
221222

223+
("type_overflow",
224+
LintSpec {
225+
lint: type_overflow,
226+
desc: "literal out of range for its type",
227+
default: warn
228+
}),
229+
230+
222231
("unused_unsafe",
223232
LintSpec {
224233
lint: unused_unsafe,
@@ -321,6 +330,9 @@ struct Context {
321330
// levels, this stack keeps track of the previous lint levels of whatever
322331
// was modified.
323332
lint_stack: ~[(lint, level, LintSource)],
333+
334+
// id of the last visited negated expression
335+
negated_expr_id: ast::NodeId
324336
}
325337

326338
impl Context {
@@ -507,7 +519,48 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) {
507519
cx.span_lint(type_limits, e.span,
508520
"comparison is useless due to type limits");
509521
}
510-
}
522+
},
523+
ast::ExprLit(lit) => {
524+
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
525+
ty::ty_int(t) => {
526+
let int_type = if t == ast::ty_i {
527+
cx.tcx.sess.targ_cfg.int_type
528+
} else { t };
529+
let (min, max) = int_ty_range(int_type);
530+
let mut lit_val: i64 = match lit.node {
531+
ast::lit_int(v, _) => v,
532+
ast::lit_uint(v, _) => v as i64,
533+
ast::lit_int_unsuffixed(v) => v,
534+
_ => fail!()
535+
};
536+
if cx.negated_expr_id == e.id {
537+
lit_val *= -1;
538+
}
539+
if lit_val < min || lit_val > max {
540+
cx.span_lint(type_overflow, e.span,
541+
"literal out of range for its type");
542+
}
543+
},
544+
ty::ty_uint(t) => {
545+
let uint_type = if t == ast::ty_u {
546+
cx.tcx.sess.targ_cfg.uint_type
547+
} else { t };
548+
let (min, max) = uint_ty_range(uint_type);
549+
let lit_val: u64 = match lit.node {
550+
ast::lit_int(v, _) => v as u64,
551+
ast::lit_uint(v, _) => v,
552+
ast::lit_int_unsuffixed(v) => v as u64,
553+
_ => fail!()
554+
};
555+
if lit_val < min || lit_val > max {
556+
cx.span_lint(type_overflow, e.span,
557+
"literal out of range for its type");
558+
}
559+
},
560+
561+
_ => ()
562+
};
563+
},
511564
_ => ()
512565
};
513566

@@ -1078,11 +1131,25 @@ impl Visitor<()> for Context {
10781131
}
10791132

10801133
fn visit_expr(&mut self, e: @ast::Expr, _: ()) {
1134+
match e.node {
1135+
ast::ExprUnary(_, ast::UnNeg, expr) => {
1136+
// propagate negation, if the negation itself isn't negated
1137+
if self.negated_expr_id != e.id {
1138+
self.negated_expr_id = expr.id;
1139+
}
1140+
},
1141+
ast::ExprParen(expr) => if self.negated_expr_id == e.id {
1142+
self.negated_expr_id = expr.id
1143+
},
1144+
_ => ()
1145+
};
1146+
10811147
check_while_true_expr(self, e);
10821148
check_stability(self, e);
10831149
check_unused_unsafe(self, e);
10841150
check_unnecessary_allocation(self, e);
10851151
check_heap_expr(self, e);
1152+
10861153
check_type_limits(self, e);
10871154

10881155
visit::walk_expr(self, e, ());
@@ -1139,6 +1206,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: &ast::Crate) {
11391206
cur: SmallIntMap::new(),
11401207
tcx: tcx,
11411208
lint_stack: ~[],
1209+
negated_expr_id: -1
11421210
};
11431211

11441212
// Install default lint levels, followed by the command line levels, and

src/test/compile-fail/lint-type-limits.rs

+2
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ fn bar() -> i8 {
2424

2525
fn baz() -> bool {
2626
128 > bar() //~ ERROR comparison is useless due to type limits
27+
//~^ WARNING literal out of range for its type
2728
}
2829

2930
fn qux() {
3031
let mut i = 1i8;
3132
while 200 != i { //~ ERROR comparison is useless due to type limits
33+
//~^ WARNING literal out of range for its type
3234
i += 1;
3335
}
3436
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
12+
#[deny(type_overflow)];
13+
14+
fn test(x: i8) {
15+
println!("x {}", x);
16+
}
17+
18+
#[allow(unused_variable)]
19+
fn main() {
20+
let x1: u8 = 255; // should be OK
21+
let x1: u8 = 256; //~ error: literal out of range for its type
22+
23+
let x1 = 255_u8; // should be OK
24+
let x1 = 256_u8; //~ error: literal out of range for its type
25+
26+
let x2: i8 = -128; // should be OK
27+
let x1: i8 = 128; //~ error: literal out of range for its type
28+
let x2: i8 = --128; //~ error: literal out of range for its type
29+
30+
let x3: i8 = -129; //~ error: literal out of range for its type
31+
let x3: i8 = -(129); //~ error: literal out of range for its type
32+
let x3: i8 = -{129}; //~ error: literal out of range for its type
33+
34+
test(1000); //~ error: literal out of range for its type
35+
36+
let x = 128_i8; //~ error: literal out of range for its type
37+
let x = 127_i8;
38+
let x = -128_i8;
39+
let x = -(128_i8);
40+
let x = -129_i8; //~ error: literal out of range for its type
41+
42+
let x: i32 = 2147483647; // should be OK
43+
let x = 2147483647_i32; // should be OK
44+
let x: i32 = 2147483648; //~ error: literal out of range for its type
45+
let x = 2147483648_i32; //~ error: literal out of range for its type
46+
let x: i32 = -2147483648; // should be OK
47+
let x = -2147483648_i32; // should be OK
48+
let x: i32 = -2147483649; //~ error: literal out of range for its type
49+
let x = -2147483649_i32; //~ error: literal out of range for its type
50+
}

src/test/compile-fail/oversized-literal.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern:literal out of range
11+
// compile-flags: -D type-overflow
1212

13-
fn main() { info!("{}", 300u8); }
13+
fn main() { info!("{}", 300u8); } //~ error: literal out of range for its type

0 commit comments

Comments
 (0)