diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 71f39a77e362..eb4f74105f29 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -148,7 +148,8 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, impl_map, crate)); time(time_passes, "const checking", - bind middle::check_const::check_crate(sess, crate, method_map)); + bind middle::check_const::check_crate(sess, crate, method_map, + ty_cx)); if upto == cu_typeck { ret {crate: crate, tcx: some(ty_cx)}; } diff --git a/src/rustc/middle/check_alt.rs b/src/rustc/middle/check_alt.rs index 74c8250b2368..334535efb42b 100644 --- a/src/rustc/middle/check_alt.rs +++ b/src/rustc/middle/check_alt.rs @@ -258,19 +258,19 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { } pat_lit(la) { alt b.node { - pat_lit(lb) { lit_expr_eq(la, lb) } + pat_lit(lb) { lit_expr_eq(tcx, la, lb) } _ { false } } } pat_range(begina, enda) { alt b.node { pat_lit(lb) { - compare_lit_exprs(begina, lb) <= 0 && - compare_lit_exprs(enda, lb) >= 0 + compare_lit_exprs(tcx, begina, lb) <= 0 && + compare_lit_exprs(tcx, enda, lb) >= 0 } pat_range(beginb, endb) { - compare_lit_exprs(begina, beginb) <= 0 && - compare_lit_exprs(enda, endb) >= 0 + compare_lit_exprs(tcx, begina, beginb) <= 0 && + compare_lit_exprs(tcx, enda, endb) >= 0 } _ { false } } diff --git a/src/rustc/middle/check_const.rs b/src/rustc/middle/check_const.rs index c36aeaede76a..9098bf1fc11b 100644 --- a/src/rustc/middle/check_const.rs +++ b/src/rustc/middle/check_const.rs @@ -3,11 +3,12 @@ import syntax::{visit, ast_util}; import driver::session::session; import std::map::hashmap; -fn check_crate(sess: session, crate: @crate, method_map: typeck::method_map) { +fn check_crate(sess: session, crate: @crate, method_map: typeck::method_map, + tcx: ty::ctxt) { visit::visit_crate(*crate, false, visit::mk_vt(@{ visit_item: check_item, visit_pat: check_pat, - visit_expr: bind check_expr(sess, method_map, _, _, _) + visit_expr: bind check_expr(sess, method_map, tcx, _, _, _) with *visit::default_visitor() })); sess.abort_if_errors(); @@ -42,8 +43,8 @@ fn check_pat(p: @pat, &&_is_const: bool, v: visit::vt) { } } -fn check_expr(sess: session, method_map: typeck::method_map, e: @expr, - &&is_const: bool, v: visit::vt) { +fn check_expr(sess: session, method_map: typeck::method_map, tcx: ty::ctxt, + e: @expr, &&is_const: bool, v: visit::vt) { if is_const { alt e.node { expr_unary(box(_), _) | expr_unary(uniq(_), _) | @@ -63,6 +64,14 @@ fn check_expr(sess: session, method_map: typeck::method_map, e: @expr, } } expr_lit(_) {} + expr_cast(_, _) { + let ety = ty::expr_ty(tcx, e); + if !ty::type_is_numeric(ety) { + sess.span_err(e.span, "can not cast to `" + + util::ppaux::ty_to_str(tcx, ety) + + "` in a constant expression"); + } + } _ { sess.span_err(e.span, "constant contains unimplemented expression type"); diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index fcdaf71acfaf..eeb2c4136cf3 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -23,12 +23,12 @@ enum opt { var(/* disr val */int, /* variant dids */{enm: def_id, var: def_id}), range(@ast::expr, @ast::expr) } -fn opt_eq(a: opt, b: opt) -> bool { +fn opt_eq(tcx: ty::ctxt, a: opt, b: opt) -> bool { alt (a, b) { - (lit(a), lit(b)) { ast_util::compare_lit_exprs(a, b) == 0 } + (lit(a), lit(b)) { ast_util::compare_lit_exprs(tcx, a, b) == 0 } (range(a1, a2), range(b1, b2)) { - ast_util::compare_lit_exprs(a1, b1) == 0 && - ast_util::compare_lit_exprs(a2, b2) == 0 + ast_util::compare_lit_exprs(tcx, a1, b1) == 0 && + ast_util::compare_lit_exprs(tcx, a2, b2) == 0 } (var(a, _), var(b, _)) { a == b } _ { false } @@ -161,18 +161,18 @@ fn enter_opt(tcx: ty::ctxt, m: match, opt: opt, col: uint, enter_match(tcx.def_map, m, col, val) {|p| alt p.node { ast::pat_enum(_, subpats) { - if opt_eq(variant_opt(tcx, p.id), opt) { some(subpats) } + if opt_eq(tcx, variant_opt(tcx, p.id), opt) { some(subpats) } else { none } } ast::pat_ident(_, none) if pat_is_variant(tcx.def_map, p) { - if opt_eq(variant_opt(tcx, p.id), opt) { some([]) } + if opt_eq(tcx, variant_opt(tcx, p.id), opt) { some([]) } else { none } } ast::pat_lit(l) { - if opt_eq(lit(l), opt) { some([]) } else { none } + if opt_eq(tcx, lit(l), opt) { some([]) } else { none } } ast::pat_range(l1, l2) { - if opt_eq(range(l1, l2), opt) { some([]) } else { none } + if opt_eq(tcx, range(l1, l2), opt) { some([]) } else { none } } _ { some(vec::from_elem(variant_size, dummy)) } } @@ -232,8 +232,8 @@ fn enter_uniq(dm: def_map, m: match, col: uint, val: ValueRef) -> match { } fn get_options(ccx: crate_ctxt, m: match, col: uint) -> [opt] { - fn add_to_set(&set: [opt], val: opt) { - for l in set { if opt_eq(l, val) { ret; } } + fn add_to_set(tcx: ty::ctxt, &set: [opt], val: opt) { + for l in set { if opt_eq(tcx, l, val) { ret; } } set += [val]; } @@ -241,12 +241,12 @@ fn get_options(ccx: crate_ctxt, m: match, col: uint) -> [opt] { for br in m { let cur = br.pats[col]; if pat_is_variant(ccx.tcx.def_map, cur) { - add_to_set(found, variant_opt(ccx.tcx, br.pats[col].id)); + add_to_set(ccx.tcx, found, variant_opt(ccx.tcx, br.pats[col].id)); } else { alt cur.node { - ast::pat_lit(l) { add_to_set(found, lit(l)); } + ast::pat_lit(l) { add_to_set(ccx.tcx, found, lit(l)); } ast::pat_range(l1, l2) { - add_to_set(found, range(l1, l2)); + add_to_set(ccx.tcx, found, range(l1, l2)); } _ {} } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 67723337cfb5..a4a2c9cfcd4e 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2592,6 +2592,17 @@ fn float_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, } else { llsrc }; } +enum cast_kind { cast_pointer, cast_integral, cast_float, + cast_enum, cast_other, } +fn cast_type_kind(t: ty::t) -> cast_kind { + if ty::type_is_fp(t) { cast_float } + else if ty::type_is_unsafe_ptr(t) { cast_pointer } + else if ty::type_is_integral(t) { cast_integral } + else if ty::type_is_enum(t) { cast_enum } + else { cast_other } +} + + fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id, dest: dest) -> block { let ccx = cx.ccx(); @@ -2605,55 +2616,48 @@ fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id, let t_in = expr_ty(cx, e); let ll_t_out = type_of(ccx, t_out); - enum kind { pointer, integral, float, enum_, other, } - fn t_kind(t: ty::t) -> kind { - ret if ty::type_is_fp(t) { float } - else if ty::type_is_unsafe_ptr(t) { pointer } - else if ty::type_is_integral(t) { integral } - else if ty::type_is_enum(t) { enum_ } - else { other }; - } - let k_in = t_kind(t_in); - let k_out = t_kind(t_out); - let s_in = k_in == integral && ty::type_is_signed(t_in); + let k_in = cast_type_kind(t_in); + let k_out = cast_type_kind(t_out); + let s_in = k_in == cast_integral && ty::type_is_signed(t_in); let newval = alt {in: k_in, out: k_out} { - {in: integral, out: integral} { + {in: cast_integral, out: cast_integral} { int_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val, s_in) } - {in: float, out: float} { + {in: cast_float, out: cast_float} { float_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val) } - {in: integral, out: float} { + {in: cast_integral, out: cast_float} { if s_in { SIToFP(e_res.bcx, e_res.val, ll_t_out) } else { UIToFP(e_res.bcx, e_res.val, ll_t_out) } } - {in: float, out: integral} { + {in: cast_float, out: cast_integral} { if ty::type_is_signed(t_out) { FPToSI(e_res.bcx, e_res.val, ll_t_out) } else { FPToUI(e_res.bcx, e_res.val, ll_t_out) } } - {in: integral, out: pointer} { + {in: cast_integral, out: cast_pointer} { IntToPtr(e_res.bcx, e_res.val, ll_t_out) } - {in: pointer, out: integral} { + {in: cast_pointer, out: cast_integral} { PtrToInt(e_res.bcx, e_res.val, ll_t_out) } - {in: pointer, out: pointer} { + {in: cast_pointer, out: cast_pointer} { PointerCast(e_res.bcx, e_res.val, ll_t_out) } - {in: enum_, out: integral} | {in: enum_, out: float} { + {in: cast_enum, out: cast_integral} | + {in: cast_enum, out: cast_float} { let cx = e_res.bcx; let llenumty = T_opaque_enum_ptr(ccx); let av_enum = PointerCast(cx, e_res.val, llenumty); let lldiscrim_a_ptr = GEPi(cx, av_enum, [0, 0]); let lldiscrim_a = Load(cx, lldiscrim_a_ptr); alt k_out { - integral {int_cast(e_res.bcx, ll_t_out, - val_ty(lldiscrim_a), lldiscrim_a, true)} - float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)} + cast_integral {int_cast(e_res.bcx, ll_t_out, + val_ty(lldiscrim_a), lldiscrim_a, true)} + cast_float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)} _ { ccx.sess.bug("translating unsupported cast.") } } } @@ -4335,6 +4339,26 @@ fn trans_const_expr(cx: crate_ctxt, e: @ast::expr) -> ValueRef { } } } + ast::expr_cast(base, tp) { + let ety = ty::expr_ty(cx.tcx, e), llty = type_of(cx, ety); + let basety = ty::expr_ty(cx.tcx, base); + let v = trans_const_expr(cx, base); + alt check (cast_type_kind(basety), cast_type_kind(ety)) { + (cast_integral, cast_integral) { + let s = if ty::type_is_signed(basety) { True } else { False }; + llvm::LLVMConstIntCast(v, llty, s) + } + (cast_integral, cast_float) { + if ty::type_is_signed(basety) { llvm::LLVMConstSIToFP(v, llty) } + else { llvm::LLVMConstUIToFP(v, llty) } + } + (cast_float, cast_float) { llvm::LLVMConstFPCast(v, llty) } + (cast_float, cast_integral) { + if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty) } + else { llvm::LLVMConstFPToUI(v, llty) } + } + } + } _ { cx.sess.span_bug(e.span, "bad constant expression type in trans_const_expr"); } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index dd9a86c4b6a1..e2272c429ce2 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2373,7 +2373,7 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] { alt variant.node.disr_expr { some (ex) { // FIXME: issue #1417 - disr_val = alt syntax::ast_util::eval_const_expr(ex) { + disr_val = alt syntax::ast_util::eval_const_expr(cx, ex) { ast_util::const_int(val) {val as int} _ { cx.sess.bug("tag_variants: bad disr expr"); } } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index b5e6bd776958..74f8fcca4ad9 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -1437,8 +1437,9 @@ fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t { } } -fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool { - ast_util::compare_lit_exprs(from, to) <= 0 +fn valid_range_bounds(tcx: ty::ctxt, from: @ast::expr, to: @ast::expr) + -> bool { + ast_util::compare_lit_exprs(tcx, from, to) <= 0 } fn check_pat_variant(fcx: @fn_ctxt, map: pat_util::pat_id_map, @@ -1516,7 +1517,7 @@ fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat, tcx.sess.span_err(pat.span, "mismatched types in range"); } else if !ty::type_is_numeric(b_ty) { tcx.sess.span_err(pat.span, "non-numeric type used in range"); - } else if !valid_range_bounds(begin, end) { + } else if !valid_range_bounds(tcx, begin, end) { tcx.sess.span_err(begin.span, "lower range bound must be less \ than upper"); } @@ -2913,14 +2914,14 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], alt v.node.disr_expr { some(e) { check_expr(fcx, e); - let cty = expr_ty(fcx.ccx.tcx, e); - let declty = ty::mk_int(fcx.ccx.tcx); + let cty = expr_ty(ccx.tcx, e); + let declty = ty::mk_int(ccx.tcx); demand::simple(fcx, e.span, declty, cty); // FIXME: issue #1417 // Also, check_expr (from check_const pass) doesn't guarantee that // the expression in an form that eval_const_expr can handle, so // we may still get an internal compiler error - alt syntax::ast_util::eval_const_expr(e) { + alt syntax::ast_util::eval_const_expr(ccx.tcx, e) { syntax::ast_util::const_int(val) { disr_val = val as int; } diff --git a/src/rustc/syntax/ast_util.rs b/src/rustc/syntax/ast_util.rs index a6e34f3b24d9..e5a15edf1a3f 100644 --- a/src/rustc/syntax/ast_util.rs +++ b/src/rustc/syntax/ast_util.rs @@ -250,38 +250,36 @@ enum const_val { } // FIXME: issue #1417 -fn eval_const_expr(e: @expr) -> const_val { +fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val { + import middle::ty; fn fromb(b: bool) -> const_val { const_int(b as i64) } - alt e.node { + alt check e.node { expr_unary(neg, inner) { - alt eval_const_expr(inner) { + alt check eval_const_expr(tcx, inner) { const_float(f) { const_float(-f) } const_int(i) { const_int(-i) } const_uint(i) { const_uint(-i) } - _ { fail "eval_const_expr: bad neg argument"; } } } expr_unary(not, inner) { - alt eval_const_expr(inner) { + alt check eval_const_expr(tcx, inner) { const_int(i) { const_int(!i) } const_uint(i) { const_uint(!i) } - _ { fail "eval_const_expr: bad not argument"; } } } expr_binary(op, a, b) { - alt (eval_const_expr(a), eval_const_expr(b)) { + alt check (eval_const_expr(tcx, a), eval_const_expr(tcx, b)) { (const_float(a), const_float(b)) { - alt op { + alt check op { add { const_float(a + b) } subtract { const_float(a - b) } mul { const_float(a * b) } div { const_float(a / b) } rem { const_float(a % b) } eq { fromb(a == b) } lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } ge { fromb(a >= b) } gt { fromb(a > b) } - _ { fail "eval_const_expr: can't apply this binop to floats"; } } } (const_int(a), const_int(b)) { - alt op { + alt check op { add { const_int(a + b) } subtract { const_int(a - b) } mul { const_int(a * b) } div { const_int(a / b) } rem { const_int(a % b) } and | bitand { const_int(a & b) } @@ -291,11 +289,11 @@ fn eval_const_expr(e: @expr) -> const_val { eq { fromb(a == b) } lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } ge { fromb(a >= b) } gt { fromb(a > b) } - _ { fail "eval_const_expr: can't apply this binop to ints"; } } + } (const_uint(a), const_uint(b)) { - alt op { + alt check op { add { const_uint(a + b) } subtract { const_uint(a - b) } mul { const_uint(a * b) } div { const_uint(a / b) } rem { const_uint(a % b) } and | bitand { const_uint(a & b) } @@ -306,17 +304,38 @@ fn eval_const_expr(e: @expr) -> const_val { eq { fromb(a == b) } lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } ge { fromb(a >= b) } gt { fromb(a > b) } - _ { fail "eval_const_expr: can't apply this binop to uints"; } } } - _ { fail "eval_constr_expr: bad binary arguments"; } + } + } + expr_cast(base, _) { + let ety = ty::expr_ty(tcx, e); + let base = eval_const_expr(tcx, base); + alt check ty::get(ety).struct { + ty::ty_float(_) { + alt check base { + const_uint(u) { const_float(u as f64) } + const_int(i) { const_float(i as f64) } + const_float(_) { base } + } + } + ty::ty_uint(_) { + alt check base { + const_uint(_) { base } + const_int(i) { const_uint(i as u64) } + const_float(f) { const_uint(f as u64) } + } + } + ty::ty_int(_) | ty::ty_bool { + alt check base { + const_uint(u) { const_int(u as i64) } + const_int(_) { base } + const_float(f) { const_int(f as i64) } + } + } } } expr_lit(lit) { lit_to_const(lit) } - // Precondition? - _ { - fail "eval_const_expr: non-constant expression"; - } } } @@ -375,11 +394,13 @@ fn compare_const_vals(a: const_val, b: const_val) -> int { } } -fn compare_lit_exprs(a: @expr, b: @expr) -> int { - compare_const_vals(eval_const_expr(a), eval_const_expr(b)) +fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> int { + compare_const_vals(eval_const_expr(tcx, a), eval_const_expr(tcx, b)) } -fn lit_expr_eq(a: @expr, b: @expr) -> bool { compare_lit_exprs(a, b) == 0 } +fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool { + compare_lit_exprs(tcx, a, b) == 0 +} fn lit_eq(a: @lit, b: @lit) -> bool { compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0