Skip to content

Commit 99a4866

Browse files
committed
rustc: Allow any integral types on rhs of shift ops
1 parent e9c7f0c commit 99a4866

File tree

4 files changed

+156
-8
lines changed

4 files changed

+156
-8
lines changed

src/comp/middle/trans/base.rs

+43
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,44 @@ fn trans_compare(cx: block, op: ast::binop, lhs: ValueRef,
16411641
}
16421642
}
16431643

1644+
fn cast_shift_expr_rhs(cx: block, op: ast::binop,
1645+
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
1646+
cast_shift_rhs(op, lhs, rhs,
1647+
bind Trunc(cx, _, _), bind ZExt(cx, _, _))
1648+
}
1649+
1650+
fn cast_shift_const_rhs(op: ast::binop,
1651+
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
1652+
cast_shift_rhs(op, lhs, rhs,
1653+
llvm::LLVMConstTrunc, llvm::LLVMConstZExt)
1654+
}
1655+
1656+
fn cast_shift_rhs(op: ast::binop,
1657+
lhs: ValueRef, rhs: ValueRef,
1658+
trunc: fn(ValueRef, TypeRef) -> ValueRef,
1659+
zext: fn(ValueRef, TypeRef) -> ValueRef
1660+
) -> ValueRef {
1661+
1662+
// Shifts may have any size int on the rhs
1663+
if ast_util::is_shift_binop(op) {
1664+
let rhs_llty = val_ty(rhs);
1665+
let lhs_llty = val_ty(lhs);
1666+
let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty);
1667+
let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty);
1668+
if lhs_sz < rhs_sz {
1669+
trunc(rhs, lhs_llty)
1670+
} else if lhs_sz > rhs_sz {
1671+
// FIXME: If shifting by negative values becomes not undefined
1672+
// then this is wrong.
1673+
zext(rhs, lhs_llty)
1674+
} else {
1675+
rhs
1676+
}
1677+
} else {
1678+
rhs
1679+
}
1680+
}
1681+
16441682
// Important to get types for both lhs and rhs, because one might be _|_
16451683
// and the other not.
16461684
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,
16511689
if ty::type_is_bot(intype) { intype = rhs_t; }
16521690
let is_float = ty::type_is_fp(intype);
16531691

1692+
let rhs = cast_shift_expr_rhs(cx, op, lhs, rhs);
1693+
16541694
if op == ast::add && ty::type_is_sequence(intype) {
16551695
ret tvec::trans_add(cx, intype, lhs, rhs, dest);
16561696
}
@@ -4059,6 +4099,9 @@ fn trans_const_expr(cx: crate_ctxt, e: @ast::expr) -> ValueRef {
40594099
ast::expr_binary(b, e1, e2) {
40604100
let te1 = trans_const_expr(cx, e1);
40614101
let te2 = trans_const_expr(cx, e2);
4102+
4103+
let te2 = cast_shift_const_rhs(b, te1, te2);
4104+
40624105
/* Neither type is bottom, and we expect them to be unified already,
40634106
* so the following is safe. */
40644107
let ty = ty::expr_ty(cx.tcx, e1);

src/comp/middle/typeck.rs

+18-8
Original file line numberDiff line numberDiff line change
@@ -2117,8 +2117,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
21172117
let lhs_t = next_ty_var(fcx);
21182118
bot = check_expr_with(fcx, lhs, lhs_t);
21192119

2120-
let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
2120+
let rhs_bot = if !ast_util::is_shift_binop(binop) {
2121+
check_expr_with(fcx, rhs, lhs_t)
2122+
} else {
2123+
let rhs_bot = check_expr(fcx, rhs);
2124+
let rhs_t = expr_ty(tcx, rhs);
2125+
require_integral(fcx, rhs.span, rhs_t);
2126+
rhs_bot
2127+
};
2128+
21212129
if !ast_util::lazy_binop(binop) { bot |= rhs_bot; }
2130+
21222131
let result = check_binop(fcx, expr, lhs_t, binop, rhs);
21232132
write_ty(tcx, id, result);
21242133
}
@@ -2572,13 +2581,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
25722581
let base_t = do_autoderef(fcx, expr.span, raw_base_t);
25732582
bot |= check_expr(fcx, idx);
25742583
let idx_t = expr_ty(tcx, idx);
2575-
fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
2576-
if !type_is_integral(fcx, sp, t) {
2577-
fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \
2578-
`integer` but found `"
2579-
+ ty_to_str(fcx.ccx.tcx, t) + "`");
2580-
}
2581-
}
25822584
alt structure_of(fcx, expr.span, base_t) {
25832585
ty::ty_vec(mt) {
25842586
require_integral(fcx, idx.span, idx_t);
@@ -2612,6 +2614,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
26122614
ret bot;
26132615
}
26142616

2617+
fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
2618+
if !type_is_integral(fcx, sp, t) {
2619+
fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \
2620+
`integer` but found `"
2621+
+ ty_to_str(fcx.ccx.tcx, t) + "`");
2622+
}
2623+
}
2624+
26152625
fn next_ty_var_id(fcx: @fn_ctxt) -> int {
26162626
let id = *fcx.next_var_id;
26172627
*fcx.next_var_id += 1;

src/comp/syntax/ast_util.rs

+9
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ pure fn lazy_binop(b: binop) -> bool {
6464
alt b { and { true } or { true } _ { false } }
6565
}
6666
67+
pure fn is_shift_binop(b: binop) -> bool {
68+
alt b {
69+
lsl { true }
70+
lsr { true }
71+
asr { true }
72+
_ { false }
73+
}
74+
}
75+
6776
fn unop_to_str(op: unop) -> str {
6877
alt op {
6978
box(mt) { if mt == m_mutbl { ret "@mut "; } ret "@"; }

src/test/run-pass/shift.rs

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Testing shifts for various combinations of integers
2+
// Issue #1570
3+
4+
fn main() {
5+
test_misc();
6+
test_expr();
7+
test_const();
8+
}
9+
10+
fn test_misc() {
11+
assert 1 << 1i8 << 1u8 << 1i16 << 1 as char << 1u64 == 32;
12+
}
13+
14+
fn test_expr() {
15+
let v10 = 10 as uint;
16+
let v4 = 4 as u8;
17+
let v2 = 2 as u8;
18+
assert (v10 >> v2 == v2 as uint);
19+
assert (v10 >>> v2 == v2 as uint);
20+
assert (v10 << v4 == 160 as uint);
21+
22+
let v10 = 10 as u8;
23+
let v4 = 4 as uint;
24+
let v2 = 2 as uint;
25+
assert (v10 >> v2 == v2 as u8);
26+
assert (v10 >>> v2 == v2 as u8);
27+
assert (v10 << v4 == 160 as u8);
28+
29+
let v10 = 10 as int;
30+
let v4 = 4 as i8;
31+
let v2 = 2 as i8;
32+
assert (v10 >> v2 == v2 as int);
33+
assert (v10 >>> v2 == v2 as int);
34+
assert (v10 << v4 == 160 as int);
35+
36+
let v10 = 10 as i8;
37+
let v4 = 4 as int;
38+
let v2 = 2 as int;
39+
assert (v10 >> v2 == v2 as i8);
40+
assert (v10 >>> v2 == v2 as i8);
41+
assert (v10 << v4 == 160 as i8);
42+
43+
let v10 = 10 as uint;
44+
let v4 = 4 as int;
45+
let v2 = 2 as int;
46+
assert (v10 >> v2 == v2 as uint);
47+
assert (v10 >>> v2 == v2 as uint);
48+
assert (v10 << v4 == 160 as uint);
49+
}
50+
51+
fn test_const() {
52+
const r1_1: uint = 10u >> 2u8;
53+
const r2_1: uint = 10u >>> 2u8;
54+
const r3_1: uint = 10u << 4u8;
55+
assert r1_1 == 2 as uint;
56+
assert r2_1 == 2 as uint;
57+
assert r3_1 == 160 as uint;
58+
59+
const r1_2: u8 = 10u8 >> 2u;
60+
const r2_2: u8 = 10u8 >>> 2u;
61+
const r3_2: u8 = 10u8 << 4u;
62+
assert r1_2 == 2 as u8;
63+
assert r2_2 == 2 as u8;
64+
assert r3_2 == 160 as u8;
65+
66+
const r1_3: int = 10 >> 2i8;
67+
const r2_3: int = 10 >>> 2i8;
68+
const r3_3: int = 10 << 4i8;
69+
assert r1_3 == 2 as int;
70+
assert r2_3 == 2 as int;
71+
assert r3_3 == 160 as int;
72+
73+
const r1_4: i8 = 10i8 >> 2;
74+
const r2_4: i8 = 10i8 >>> 2;
75+
const r3_4: i8 = 10i8 << 4;
76+
assert r1_4 == 2 as i8;
77+
assert r2_4 == 2 as i8;
78+
assert r3_4 == 160 as i8;
79+
80+
const r1_5: uint = 10u >> 2i8;
81+
const r2_5: uint = 10u >>> 2i8;
82+
const r3_5: uint = 10u << 4i8;
83+
assert r1_5 == 2 as uint;
84+
assert r2_5 == 2 as uint;
85+
assert r3_5 == 160 as uint;
86+
}

0 commit comments

Comments
 (0)