@@ -30,6 +30,7 @@ use middle::def::*;
30
30
use middle:: typeck:: astconv:: ast_ty_to_ty;
31
31
use middle:: typeck:: infer;
32
32
use middle:: { typeck, ty, def, pat_util, stability} ;
33
+ use middle:: const_eval:: { eval_const_expr_partial, const_int, const_uint} ;
33
34
use util:: ppaux:: { ty_to_string} ;
34
35
use util:: nodemap:: NodeSet ;
35
36
use lint:: { Context , LintPass , LintArray } ;
@@ -38,14 +39,16 @@ use std::cmp;
38
39
use std:: collections:: HashMap ;
39
40
use std:: collections:: hashmap:: { Occupied , Vacant } ;
40
41
use 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} ;
42
43
use syntax:: abi;
43
44
use syntax:: ast_map;
45
+ use syntax:: ast_util:: is_shift_binop;
44
46
use syntax:: attr:: AttrMetaMethods ;
45
47
use syntax:: attr;
46
48
use syntax:: codemap:: Span ;
47
49
use syntax:: parse:: token;
48
50
use syntax:: { ast, ast_util, visit} ;
51
+ use syntax:: ast:: { TyI , TyU , TyI8 , TyU8 , TyI16 , TyU16 , TyI32 , TyU32 , TyI64 , TyU64 } ;
49
52
use syntax:: ptr:: P ;
50
53
use syntax:: visit:: Visitor ;
51
54
@@ -113,6 +116,9 @@ declare_lint!(UNUSED_COMPARISONS, Warn,
113
116
declare_lint ! ( OVERFLOWING_LITERALS , Warn ,
114
117
"literal out of range for its type" )
115
118
119
+ declare_lint ! ( EXCEEDING_BITSHIFTS , Deny ,
120
+ "shift exceeds the type's number of bits" )
121
+
116
122
pub struct TypeLimits {
117
123
/// Id of the last visited negated expression
118
124
negated_expr_id : ast:: NodeId ,
@@ -128,7 +134,8 @@ impl TypeLimits {
128
134
129
135
impl LintPass for TypeLimits {
130
136
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 )
132
139
}
133
140
134
141
fn check_expr ( & mut self , cx : & Context , e : & ast:: Expr ) {
@@ -170,6 +177,31 @@ impl LintPass for TypeLimits {
170
177
cx. span_lint ( UNUSED_COMPARISONS , e. span ,
171
178
"comparison is useless due to type limits" ) ;
172
179
}
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
+ }
173
205
} ,
174
206
ast:: ExprLit ( ref lit) => {
175
207
match ty:: get ( ty:: expr_ty ( cx. tcx , e) ) . sty {
@@ -280,6 +312,26 @@ impl LintPass for TypeLimits {
280
312
}
281
313
}
282
314
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
+
283
335
fn check_limits ( tcx : & ty:: ctxt , binop : ast:: BinOp ,
284
336
l : & ast:: Expr , r : & ast:: Expr ) -> bool {
285
337
let ( lit, expr, swap) = match ( & l. node , & r. node ) {
0 commit comments