use middle::typeck::astconv::ast_ty_to_ty;
use middle::typeck::infer;
use middle::{typeck, ty, def, pat_util, stability};
+use middle::const_eval::{eval_const_expr_partial, const_int, const_uint};
use util::ppaux::{ty_to_string};
use util::nodemap::NodeSet;
use lint::{Context, LintPass, LintArray};
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::slice;
-use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
+use std::{int, i8, i16, i32, i64, uint, u8, u16, u32, u64, f32, f64};
use syntax::abi;
use syntax::ast_map;
+use syntax::ast_util::is_shift_binop;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::{ast, ast_util, visit};
+use syntax::ast::{TyI, TyU, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
use syntax::ptr::P;
use syntax::visit::Visitor;
declare_lint!(OVERFLOWING_LITERALS, Warn,
"literal out of range for its type")
+declare_lint!(EXCEEDING_BITSHIFTS, Deny,
+ "shift exceeds the type's number of bits")
+
pub struct TypeLimits {
/// Id of the last visited negated expression
negated_expr_id: ast::NodeId,
impl LintPass for TypeLimits {
fn get_lints(&self) -> LintArray {
- lint_array!(UNSIGNED_NEGATION, UNUSED_COMPARISONS, OVERFLOWING_LITERALS)
+ lint_array!(UNSIGNED_NEGATION, UNUSED_COMPARISONS, OVERFLOWING_LITERALS,
+ EXCEEDING_BITSHIFTS)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
cx.span_lint(UNUSED_COMPARISONS, e.span,
"comparison is useless due to type limits");
}
+
+ if is_shift_binop(binop) {
+ let opt_ty_bits = match ty::get(ty::expr_ty(cx.tcx, &**l)).sty {
+ ty::ty_int(t) => Some(int_ty_bits(t)),
+ ty::ty_uint(t) => Some(uint_ty_bits(t)),
+ _ => None
+ };
+
+ if let Some(bits) = opt_ty_bits {
+ let exceeding = if let ast::ExprLit(ref lit) = r.node {
+ if let ast::LitInt(shift, _) = lit.node { shift > bits }
+ else { false }
+ } else {
+ match eval_const_expr_partial(cx.tcx, &**r) {
+ Ok(const_int(shift)) => { shift as u64 > bits },
+ Ok(const_uint(shift)) => { shift > bits },
+ _ => { false }
+ }
+ };
+ if exceeding {
+ cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
+ "bitshift exceeds the type's number of bits");
+ }
+ };
+ }
},
ast::ExprLit(ref lit) => {
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
}
}
+ fn int_ty_bits(int_ty: ast::IntTy) -> u64 {
+ match int_ty {
+ ast::TyI => int::BITS as u64,
+ ast::TyI8 => i8::BITS as u64,
+ ast::TyI16 => i16::BITS as u64,
+ ast::TyI32 => i32::BITS as u64,
+ ast::TyI64 => i64::BITS as u64
+ }
+ }
+
+ fn uint_ty_bits(uint_ty: ast::UintTy) -> u64 {
+ match uint_ty {
+ ast::TyU => uint::BITS as u64,
+ ast::TyU8 => u8::BITS as u64,
+ ast::TyU16 => u16::BITS as u64,
+ ast::TyU32 => u32::BITS as u64,
+ ast::TyU64 => u64::BITS as u64
+ }
+ }
+
fn check_limits(tcx: &ty::ctxt, binop: ast::BinOp,
l: &ast::Expr, r: &ast::Expr) -> bool {
let (lit, expr, swap) = match (&l.node, &r.node) {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(exceeding_bitshifts)]
+#![allow(unused_variables)]
+
+fn main() {
+ let n = 1u8 << 8;
+ let n = 1u8 << 9; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1u16 << 16;
+ let n = 1u16 << 17; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1u32 << 32;
+ let n = 1u32 << 33; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1u64 << 64;
+ let n = 1u64 << 65; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i8 << 8;
+ let n = 1i8 << 9; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i16 << 16;
+ let n = 1i16 << 17; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i32 << 32;
+ let n = 1i32 << 33; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i64 << 64;
+ let n = 1i64 << 65; //~ ERROR: bitshift exceeds the type's number of bits
+
+ let n = 1u8 >> 8;
+ let n = 1u8 >> 9; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1u16 >> 16;
+ let n = 1u16 >> 17; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1u32 >> 32;
+ let n = 1u32 >> 33; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1u64 >> 64;
+ let n = 1u64 >> 65; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i8 >> 8;
+ let n = 1i8 >> 9; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i16 >> 16;
+ let n = 1i16 >> 17; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i32 >> 32;
+ let n = 1i32 >> 33; //~ ERROR: bitshift exceeds the type's number of bits
+ let n = 1i64 >> 64;
+ let n = 1i64 >> 65; //~ ERROR: bitshift exceeds the type's number of bits
+
+ let n = 1u8;
+ let n = n << 8;
+ let n = n << 9; //~ ERROR: bitshift exceeds the type's number of bits
+
+ let n = 1u8 << -9; //~ ERROR: bitshift exceeds the type's number of bits
+
+ let n = 1u8 << (4+4);
+ let n = 1u8 << (4+5); //~ ERROR: bitshift exceeds the type's number of bits
+}
+