about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-02-21 21:01:33 -0800
committerBrian Anderson <banderson@mozilla.com>2012-02-22 17:26:08 -0800
commit99a48660d1a9c124e7b2f738c51641dddf1adf6f (patch)
tree5794599355c6f4eabd475a7adb09f2a01430601f /src/comp
parente9c7f0c2ba507fdfbb899f2144c2974049007eba (diff)
rustc: Allow any integral types on rhs of shift ops
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/trans/base.rs43
-rw-r--r--src/comp/middle/typeck.rs26
-rw-r--r--src/comp/syntax/ast_util.rs9
3 files changed, 70 insertions, 8 deletions
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index a86681da8ce..4ec06b83772 100644
--- a/src/comp/middle/trans/base.rs
+++ b/src/comp/middle/trans/base.rs
@@ -1641,6 +1641,44 @@ fn trans_compare(cx: block, op: ast::binop, lhs: ValueRef,
     }
 }
 
+fn cast_shift_expr_rhs(cx: block, op: ast::binop,
+                       lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+    cast_shift_rhs(op, lhs, rhs,
+                   bind Trunc(cx, _, _), bind ZExt(cx, _, _))
+}
+
+fn cast_shift_const_rhs(op: ast::binop,
+                        lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+    cast_shift_rhs(op, lhs, rhs,
+                   llvm::LLVMConstTrunc, llvm::LLVMConstZExt)
+}
+
+fn cast_shift_rhs(op: ast::binop,
+                  lhs: ValueRef, rhs: ValueRef,
+                  trunc: fn(ValueRef, TypeRef) -> ValueRef,
+                  zext: fn(ValueRef, TypeRef) -> ValueRef
+                 ) -> ValueRef {
+
+    // Shifts may have any size int on the rhs
+    if ast_util::is_shift_binop(op) {
+        let rhs_llty = val_ty(rhs);
+        let lhs_llty = val_ty(lhs);
+        let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty);
+        let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty);
+        if lhs_sz < rhs_sz {
+            trunc(rhs, lhs_llty)
+        } else if lhs_sz > rhs_sz {
+            // FIXME: If shifting by negative values becomes not undefined
+            // then this is wrong.
+            zext(rhs, lhs_llty)
+        } else {
+            rhs
+        }
+    } else {
+        rhs
+    }
+}
+
 // Important to get types for both lhs and rhs, because one might be _|_
 // and the other not.
 fn trans_eager_binop(cx: block, op: ast::binop, lhs: ValueRef,
@@ -1651,6 +1689,8 @@ fn trans_eager_binop(cx: block, op: ast::binop, lhs: ValueRef,
     if ty::type_is_bot(intype) { intype = rhs_t; }
     let is_float = ty::type_is_fp(intype);
 
+    let rhs = cast_shift_expr_rhs(cx, op, lhs, rhs);
+
     if op == ast::add && ty::type_is_sequence(intype) {
         ret tvec::trans_add(cx, intype, lhs, rhs, dest);
     }
@@ -4059,6 +4099,9 @@ fn trans_const_expr(cx: crate_ctxt, e: @ast::expr) -> ValueRef {
       ast::expr_binary(b, e1, e2) {
         let te1 = trans_const_expr(cx, e1);
         let te2 = trans_const_expr(cx, e2);
+
+        let te2 = cast_shift_const_rhs(b, te1, te2);
+
         /* Neither type is bottom, and we expect them to be unified already,
          * so the following is safe. */
         let ty = ty::expr_ty(cx.tcx, e1);
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 75f3deb670f..88753b06091 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -2117,8 +2117,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         let lhs_t = next_ty_var(fcx);
         bot = check_expr_with(fcx, lhs, lhs_t);
 
-        let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
+        let rhs_bot = if !ast_util::is_shift_binop(binop) {
+            check_expr_with(fcx, rhs, lhs_t)
+        } else {
+            let rhs_bot = check_expr(fcx, rhs);
+            let rhs_t = expr_ty(tcx, rhs);
+            require_integral(fcx, rhs.span, rhs_t);
+            rhs_bot
+        };
+
         if !ast_util::lazy_binop(binop) { bot |= rhs_bot; }
+
         let result = check_binop(fcx, expr, lhs_t, binop, rhs);
         write_ty(tcx, id, result);
       }
@@ -2572,13 +2581,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         let base_t = do_autoderef(fcx, expr.span, raw_base_t);
         bot |= check_expr(fcx, idx);
         let idx_t = expr_ty(tcx, idx);
-        fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
-            if !type_is_integral(fcx, sp, t) {
-                fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \
-                                               `integer` but found `"
-                                  + ty_to_str(fcx.ccx.tcx, t) + "`");
-            }
-        }
         alt structure_of(fcx, expr.span, base_t) {
           ty::ty_vec(mt) {
             require_integral(fcx, idx.span, idx_t);
@@ -2612,6 +2614,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     ret bot;
 }
 
+fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
+    if !type_is_integral(fcx, sp, t) {
+        fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \
+                                       `integer` but found `"
+                                  + ty_to_str(fcx.ccx.tcx, t) + "`");
+    }
+}
+
 fn next_ty_var_id(fcx: @fn_ctxt) -> int {
     let id = *fcx.next_var_id;
     *fcx.next_var_id += 1;
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index b9d48cb5fb0..446f74c8680 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -64,6 +64,15 @@ pure fn lazy_binop(b: binop) -> bool {
     alt b { and { true } or { true } _ { false } }
 }
 
+pure fn is_shift_binop(b: binop) -> bool {
+    alt b {
+      lsl { true }
+      lsr { true }
+      asr { true }
+      _ { false }
+    }
+}
+
 fn unop_to_str(op: unop) -> str {
     alt op {
       box(mt) { if mt == m_mutbl { ret "@mut "; } ret "@"; }