@@ -30,6 +30,7 @@ use middle::def::*;
3030use middle:: typeck:: astconv:: ast_ty_to_ty;
3131use middle:: typeck:: infer;
3232use middle:: { typeck, ty, def, pat_util, stability} ;
33+ use middle:: const_eval:: { eval_const_expr_partial, const_int, const_uint} ;
3334use util:: ppaux:: { ty_to_string} ;
3435use util:: nodemap:: NodeSet ;
3536use lint:: { Context , LintPass , LintArray } ;
@@ -38,14 +39,16 @@ use std::cmp;
3839use std:: collections:: HashMap ;
3940use std:: collections:: hashmap:: { Occupied , Vacant } ;
4041use std:: slice;
41- use std:: { i8, i16, i32, i64, u8, u16, u32, u64, f32, f64} ;
42+ use std:: { int , i8, i16, i32, i64, uint , u8, u16, u32, u64, f32, f64} ;
4243use syntax:: abi;
4344use syntax:: ast_map;
45+ use syntax:: ast_util:: is_shift_binop;
4446use syntax:: attr:: AttrMetaMethods ;
4547use syntax:: attr;
4648use syntax:: codemap:: Span ;
4749use syntax:: parse:: token;
4850use syntax:: { ast, ast_util, visit} ;
51+ use syntax:: ast:: { TyI , TyU , TyI8 , TyU8 , TyI16 , TyU16 , TyI32 , TyU32 , TyI64 , TyU64 } ;
4952use syntax:: ptr:: P ;
5053use syntax:: visit:: Visitor ;
5154
@@ -113,6 +116,9 @@ declare_lint!(UNUSED_COMPARISONS, Warn,
113116declare_lint ! ( OVERFLOWING_LITERALS , Warn ,
114117 "literal out of range for its type" )
115118
119+ declare_lint ! ( EXCEEDING_BITSHIFTS , Deny ,
120+ "shift exceeds the type's number of bits" )
121+
116122pub struct TypeLimits {
117123 /// Id of the last visited negated expression
118124 negated_expr_id : ast:: NodeId ,
@@ -128,7 +134,8 @@ impl TypeLimits {
128134
129135impl LintPass for TypeLimits {
130136 fn get_lints ( & self ) -> LintArray {
131- lint_array ! ( UNSIGNED_NEGATION , UNUSED_COMPARISONS , OVERFLOWING_LITERALS )
137+ lint_array ! ( UNSIGNED_NEGATION , UNUSED_COMPARISONS , OVERFLOWING_LITERALS ,
138+ EXCEEDING_BITSHIFTS )
132139 }
133140
134141 fn check_expr ( & mut self , cx : & Context , e : & ast:: Expr ) {
@@ -170,6 +177,31 @@ impl LintPass for TypeLimits {
170177 cx. span_lint ( UNUSED_COMPARISONS , e. span ,
171178 "comparison is useless due to type limits" ) ;
172179 }
180+
181+ if is_shift_binop ( binop) {
182+ let opt_ty_bits = match ty:: get ( ty:: expr_ty ( cx. tcx , & * * l) ) . sty {
183+ ty:: ty_int( t) => Some ( int_ty_bits ( t) ) ,
184+ ty:: ty_uint( t) => Some ( uint_ty_bits ( t) ) ,
185+ _ => None
186+ } ;
187+
188+ if let Some ( bits) = opt_ty_bits {
189+ let exceeding = if let ast:: ExprLit ( ref lit) = r. node {
190+ if let ast:: LitInt ( shift, _) = lit. node { shift > bits }
191+ else { false }
192+ } else {
193+ match eval_const_expr_partial ( cx. tcx , & * * r) {
194+ Ok ( const_int( shift) ) => { shift as u64 > bits } ,
195+ Ok ( const_uint( shift) ) => { shift > bits } ,
196+ _ => { false }
197+ }
198+ } ;
199+ if exceeding {
200+ cx. span_lint ( EXCEEDING_BITSHIFTS , e. span ,
201+ "bitshift exceeds the type's number of bits" ) ;
202+ }
203+ } ;
204+ }
173205 } ,
174206 ast:: ExprLit ( ref lit) => {
175207 match ty:: get ( ty:: expr_ty ( cx. tcx , e) ) . sty {
@@ -280,6 +312,26 @@ impl LintPass for TypeLimits {
280312 }
281313 }
282314
315+ fn int_ty_bits ( int_ty : ast:: IntTy ) -> u64 {
316+ match int_ty {
317+ ast:: TyI => int:: BITS as u64 ,
318+ ast:: TyI8 => i8:: BITS as u64 ,
319+ ast:: TyI16 => i16:: BITS as u64 ,
320+ ast:: TyI32 => i32:: BITS as u64 ,
321+ ast:: TyI64 => i64:: BITS as u64
322+ }
323+ }
324+
325+ fn uint_ty_bits ( uint_ty : ast:: UintTy ) -> u64 {
326+ match uint_ty {
327+ ast:: TyU => uint:: BITS as u64 ,
328+ ast:: TyU8 => u8:: BITS as u64 ,
329+ ast:: TyU16 => u16:: BITS as u64 ,
330+ ast:: TyU32 => u32:: BITS as u64 ,
331+ ast:: TyU64 => u64:: BITS as u64
332+ }
333+ }
334+
283335 fn check_limits ( tcx : & ty:: ctxt , binop : ast:: BinOp ,
284336 l : & ast:: Expr , r : & ast:: Expr ) -> bool {
285337 let ( lit, expr, swap) = match ( & l. node , & r. node ) {
0 commit comments