@@ -73,6 +73,7 @@ pub enum lint {
73
73
non_uppercase_statics,
74
74
non_uppercase_pattern_statics,
75
75
type_limits,
76
+ type_overflow,
76
77
unused_unsafe,
77
78
78
79
managed_heap_memory,
@@ -220,6 +221,14 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
220
221
default : warn
221
222
} ) ,
222
223
224
+ ( "type_overflow" ,
225
+ LintSpec {
226
+ lint : type_overflow,
227
+ desc : "literal out of range for its type" ,
228
+ default : warn
229
+ } ) ,
230
+
231
+
223
232
( "unused_unsafe" ,
224
233
LintSpec {
225
234
lint : unused_unsafe,
@@ -329,6 +338,9 @@ struct Context<'self> {
329
338
// levels, this stack keeps track of the previous lint levels of whatever
330
339
// was modified.
331
340
lint_stack : ~[ ( lint , level , LintSource ) ] ,
341
+
342
+ // id of the last visited negated expression
343
+ negated_expr_id : ast:: NodeId
332
344
}
333
345
334
346
impl < ' self > Context < ' self > {
@@ -522,7 +534,48 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) {
522
534
cx. span_lint ( type_limits, e. span ,
523
535
"comparison is useless due to type limits" ) ;
524
536
}
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
+ } ,
526
579
_ => ( )
527
580
} ;
528
581
@@ -1052,11 +1105,25 @@ impl<'self> Visitor<()> for Context<'self> {
1052
1105
}
1053
1106
1054
1107
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
+
1055
1121
check_while_true_expr ( self , e) ;
1056
1122
check_stability ( self , e) ;
1057
1123
check_unused_unsafe ( self , e) ;
1058
1124
check_unnecessary_allocation ( self , e) ;
1059
1125
check_heap_expr ( self , e) ;
1126
+
1060
1127
check_type_limits ( self , e) ;
1061
1128
1062
1129
visit:: walk_expr ( self , e, ( ) ) ;
@@ -1150,6 +1217,7 @@ pub fn check_crate(tcx: ty::ctxt,
1150
1217
cur_struct_def_id : -1 ,
1151
1218
is_doc_hidden : false ,
1152
1219
lint_stack : ~[ ] ,
1220
+ negated_expr_id : -1
1153
1221
} ;
1154
1222
1155
1223
// Install default lint levels, followed by the command line levels, and
0 commit comments