]> git.lizzy.rs Git - rust.git/commitdiff
Add lint for checking exceeding bitshifts #17713
authorFalco Hirschenberger <falco.hirschenberger@gmail.com>
Sat, 1 Nov 2014 08:10:02 +0000 (09:10 +0100)
committerFalco Hirschenberger <falco.hirschenberger@gmail.com>
Sat, 1 Nov 2014 08:10:10 +0000 (09:10 +0100)
src/librustc/lint/builtin.rs
src/test/compile-fail/huge-array-simple.rs
src/test/compile-fail/lint-exceeding-bitshifts.rs [new file with mode: 0644]

index 3e53620cbd4757ff9a26e299b42b77b839c5c707..76ef6206d64164cbd76efb183d28f6621f506ff8 100644 (file)
@@ -30,6 +30,7 @@
 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;
 
@@ -113,6 +116,9 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
 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,
@@ -128,7 +134,8 @@ pub fn new() -> TypeLimits {
 
 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) {
@@ -170,6 +177,31 @@ 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 {
@@ -280,6 +312,26 @@ fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
             }
         }
 
+        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) {
index b23d0716e6ddbb12a2786f6985b474f95819f385..17f85c7bd2b8d6ba0f6240a44e10aff59321f55b 100644 (file)
@@ -11,5 +11,5 @@
 // error-pattern: too big for the current
 
 fn main() {
-   let fat : [u8, ..(1<<61)+(1<<31)] = [0, ..(1<<61)+(1<<31)];
+   let fat : [u8, ..(1<<61)+(1<<31)] = [0, ..(1u64<<61) as uint +(1u64<<31) as uint];
 }
diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs
new file mode 100644 (file)
index 0000000..f270994
--- /dev/null
@@ -0,0 +1,58 @@
+// 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
+}
+