Skip to content

Commit e5058a8

Browse files
Add lint for checking exceeding bitshifts #17713
1 parent 51a25c7 commit e5058a8

File tree

3 files changed

+113
-3
lines changed

3 files changed

+113
-3
lines changed

src/librustc/lint/builtin.rs

+54-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use middle::def::*;
3030
use middle::typeck::astconv::ast_ty_to_ty;
3131
use middle::typeck::infer;
3232
use middle::{typeck, ty, def, pat_util, stability};
33+
use middle::const_eval::{eval_const_expr_partial, const_int, const_uint};
3334
use util::ppaux::{ty_to_string};
3435
use util::nodemap::NodeSet;
3536
use lint::{Context, LintPass, LintArray};
@@ -38,14 +39,16 @@ use std::cmp;
3839
use std::collections::HashMap;
3940
use std::collections::hashmap::{Occupied, Vacant};
4041
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};
4243
use syntax::abi;
4344
use syntax::ast_map;
45+
use syntax::ast_util::is_shift_binop;
4446
use syntax::attr::AttrMetaMethods;
4547
use syntax::attr;
4648
use syntax::codemap::Span;
4749
use syntax::parse::token;
4850
use syntax::{ast, ast_util, visit};
51+
use syntax::ast::{TyI, TyU, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
4952
use syntax::ptr::P;
5053
use syntax::visit::Visitor;
5154

@@ -113,6 +116,9 @@ declare_lint!(UNUSED_COMPARISONS, Warn,
113116
declare_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+
116122
pub struct TypeLimits {
117123
/// Id of the last visited negated expression
118124
negated_expr_id: ast::NodeId,
@@ -128,7 +134,8 @@ impl TypeLimits {
128134

129135
impl 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) {

src/test/compile-fail/huge-array-simple.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
// error-pattern: too big for the current
1212

1313
fn main() {
14-
let fat : [u8, ..(1<<61)+(1<<31)] = [0, ..(1<<61)+(1<<31)];
14+
let fat : [u8, ..(1<<61)+(1<<31)] = [0, ..(1u64<<61) as uint +(1u64<<31) as uint];
1515
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2014 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+
#![deny(exceeding_bitshifts)]
12+
#![allow(unused_variables)]
13+
14+
fn main() {
15+
let n = 1u8 << 8;
16+
let n = 1u8 << 9; //~ ERROR: bitshift exceeds the type's number of bits
17+
let n = 1u16 << 16;
18+
let n = 1u16 << 17; //~ ERROR: bitshift exceeds the type's number of bits
19+
let n = 1u32 << 32;
20+
let n = 1u32 << 33; //~ ERROR: bitshift exceeds the type's number of bits
21+
let n = 1u64 << 64;
22+
let n = 1u64 << 65; //~ ERROR: bitshift exceeds the type's number of bits
23+
let n = 1i8 << 8;
24+
let n = 1i8 << 9; //~ ERROR: bitshift exceeds the type's number of bits
25+
let n = 1i16 << 16;
26+
let n = 1i16 << 17; //~ ERROR: bitshift exceeds the type's number of bits
27+
let n = 1i32 << 32;
28+
let n = 1i32 << 33; //~ ERROR: bitshift exceeds the type's number of bits
29+
let n = 1i64 << 64;
30+
let n = 1i64 << 65; //~ ERROR: bitshift exceeds the type's number of bits
31+
32+
let n = 1u8 >> 8;
33+
let n = 1u8 >> 9; //~ ERROR: bitshift exceeds the type's number of bits
34+
let n = 1u16 >> 16;
35+
let n = 1u16 >> 17; //~ ERROR: bitshift exceeds the type's number of bits
36+
let n = 1u32 >> 32;
37+
let n = 1u32 >> 33; //~ ERROR: bitshift exceeds the type's number of bits
38+
let n = 1u64 >> 64;
39+
let n = 1u64 >> 65; //~ ERROR: bitshift exceeds the type's number of bits
40+
let n = 1i8 >> 8;
41+
let n = 1i8 >> 9; //~ ERROR: bitshift exceeds the type's number of bits
42+
let n = 1i16 >> 16;
43+
let n = 1i16 >> 17; //~ ERROR: bitshift exceeds the type's number of bits
44+
let n = 1i32 >> 32;
45+
let n = 1i32 >> 33; //~ ERROR: bitshift exceeds the type's number of bits
46+
let n = 1i64 >> 64;
47+
let n = 1i64 >> 65; //~ ERROR: bitshift exceeds the type's number of bits
48+
49+
let n = 1u8;
50+
let n = n << 8;
51+
let n = n << 9; //~ ERROR: bitshift exceeds the type's number of bits
52+
53+
let n = 1u8 << -9; //~ ERROR: bitshift exceeds the type's number of bits
54+
55+
let n = 1u8 << (4+4);
56+
let n = 1u8 << (4+5); //~ ERROR: bitshift exceeds the type's number of bits
57+
}
58+

0 commit comments

Comments
 (0)