Skip to content

Commit ade310c

Browse files
committed
auto merge of #10018 : fhahn/rust/check-inferred-ints, r=alexcrichton
I've started working on this issue and pushed a small commit, which adds a range check for integer literals in `middle::const_eval` (no `uint` at the moment) At the moment, this patch is just a proof of concept, I'm not sure if there is a better function for the checks in `middle::const_eval`. This patch does not check for overflows after constant folding, eg: let x: i8 = 99 + 99;
2 parents 0d11935 + 20627c7 commit ade310c

File tree

8 files changed

+126
-21
lines changed

8 files changed

+126
-21
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/check_const.rs

-15
Original file line numberDiff line numberDiff line change
@@ -199,21 +199,6 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
199199
}
200200
}
201201
}
202-
match e.node {
203-
ExprLit(@codemap::Spanned {node: lit_int(v, t), _}) => {
204-
if (v as u64) > ast_util::int_ty_max(
205-
if t == ty_i { sess.targ_cfg.int_type } else { t }) {
206-
sess.span_err(e.span, "literal out of range for its type");
207-
}
208-
}
209-
ExprLit(@codemap::Spanned {node: lit_uint(v, t), _}) => {
210-
if v > ast_util::uint_ty_max(
211-
if t == ty_u { sess.targ_cfg.uint_type } else { t }) {
212-
sess.span_err(e.span, "literal out of range for its type");
213-
}
214-
}
215-
_ => ()
216-
}
217202
visit::walk_expr(v, e, is_const);
218203
}
219204

src/librustc/middle/lint.rs

+69-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub enum lint {
7373
non_uppercase_statics,
7474
non_uppercase_pattern_statics,
7575
type_limits,
76+
type_overflow,
7677
unused_unsafe,
7778

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

224+
("type_overflow",
225+
LintSpec {
226+
lint: type_overflow,
227+
desc: "literal out of range for its type",
228+
default: warn
229+
}),
230+
231+
223232
("unused_unsafe",
224233
LintSpec {
225234
lint: unused_unsafe,
@@ -329,6 +338,9 @@ struct Context<'self> {
329338
// levels, this stack keeps track of the previous lint levels of whatever
330339
// was modified.
331340
lint_stack: ~[(lint, level, LintSource)],
341+
342+
// id of the last visited negated expression
343+
negated_expr_id: ast::NodeId
332344
}
333345

334346
impl<'self> Context<'self> {
@@ -522,7 +534,48 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) {
522534
cx.span_lint(type_limits, e.span,
523535
"comparison is useless due to type limits");
524536
}
525-
}
537+
},
538+
ast::ExprLit(lit) => {
539+
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
540+
ty::ty_int(t) => {
541+
let int_type = if t == ast::ty_i {
542+
cx.tcx.sess.targ_cfg.int_type
543+
} else { t };
544+
let (min, max) = int_ty_range(int_type);
545+
let mut lit_val: i64 = match lit.node {
546+
ast::lit_int(v, _) => v,
547+
ast::lit_uint(v, _) => v as i64,
548+
ast::lit_int_unsuffixed(v) => v,
549+
_ => fail!()
550+
};
551+
if cx.negated_expr_id == e.id {
552+
lit_val *= -1;
553+
}
554+
if lit_val < min || lit_val > max {
555+
cx.span_lint(type_overflow, e.span,
556+
"literal out of range for its type");
557+
}
558+
},
559+
ty::ty_uint(t) => {
560+
let uint_type = if t == ast::ty_u {
561+
cx.tcx.sess.targ_cfg.uint_type
562+
} else { t };
563+
let (min, max) = uint_ty_range(uint_type);
564+
let lit_val: u64 = match lit.node {
565+
ast::lit_int(v, _) => v as u64,
566+
ast::lit_uint(v, _) => v,
567+
ast::lit_int_unsuffixed(v) => v as u64,
568+
_ => fail!()
569+
};
570+
if lit_val < min || lit_val > max {
571+
cx.span_lint(type_overflow, e.span,
572+
"literal out of range for its type");
573+
}
574+
},
575+
576+
_ => ()
577+
};
578+
},
526579
_ => ()
527580
};
528581

@@ -1052,11 +1105,25 @@ impl<'self> Visitor<()> for Context<'self> {
10521105
}
10531106

10541107
fn visit_expr(&mut self, e: @ast::Expr, _: ()) {
1108+
match e.node {
1109+
ast::ExprUnary(_, ast::UnNeg, expr) => {
1110+
// propagate negation, if the negation itself isn't negated
1111+
if self.negated_expr_id != e.id {
1112+
self.negated_expr_id = expr.id;
1113+
}
1114+
},
1115+
ast::ExprParen(expr) => if self.negated_expr_id == e.id {
1116+
self.negated_expr_id = expr.id
1117+
},
1118+
_ => ()
1119+
};
1120+
10551121
check_while_true_expr(self, e);
10561122
check_stability(self, e);
10571123
check_unused_unsafe(self, e);
10581124
check_unnecessary_allocation(self, e);
10591125
check_heap_expr(self, e);
1126+
10601127
check_type_limits(self, e);
10611128

10621129
visit::walk_expr(self, e, ());
@@ -1150,6 +1217,7 @@ pub fn check_crate(tcx: ty::ctxt,
11501217
cur_struct_def_id: -1,
11511218
is_doc_hidden: false,
11521219
lint_stack: ~[],
1220+
negated_expr_id: -1
11531221
};
11541222

11551223
// 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)