@@ -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
334346impl < ' 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
0 commit comments