diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index ec715593ce743..0c12161661aae 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -151,6 +151,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, time(time_passes, "alias checking", bind middle::alias::check_crate(ty_cx, crate)); time(time_passes, "kind checking", bind kind::check_crate(ty_cx, crate)); + time(time_passes, "const checking", + bind middle::check_const::check_crate(ty_cx, crate)); if sess.get_opts().no_trans { ret; } let llmod = time(time_passes, "translation", diff --git a/src/comp/middle/check_const.rs b/src/comp/middle/check_const.rs new file mode 100644 index 0000000000000..59bfdadf62f09 --- /dev/null +++ b/src/comp/middle/check_const.rs @@ -0,0 +1,54 @@ +import syntax::ast::*; +import syntax::ast_util::{variant_def_ids, dummy_sp}; +import syntax::visit; + +fn check_crate(tcx: ty::ctxt, crate: @crate) { + let v = + @{visit_item: bind check_item(tcx, _, _, _) + with *visit::default_visitor::<()>()}; + visit::visit_crate(*crate, (), visit::mk_vt(v)); + tcx.sess.abort_if_errors(); +} + +fn check_item(tcx: ty::ctxt, it: @item, &&s: (), v: visit::vt<()>) { + visit::visit_item(it, s, v); + alt it.node { + item_const(_ /* ty */, ex) { + let v = + @{visit_expr: bind check_const_expr(tcx, _, _, _) + with *visit::default_visitor::<()>()}; + check_const_expr(tcx, ex, (), visit::mk_vt(v)); + } + _ { } + } +} + +fn check_const_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) { + visit::visit_expr(ex, s, v); + alt ex.node { + expr_lit(_) { } + expr_binary(_, _, _) { /* subexps covered by visit */ } + expr_unary(u, _) { + alt u { + box(_) | + uniq(_) | + deref. { + tcx.sess.span_err(ex.span, + "disallowed operator in constant expression"); + } + _ { } + } + } + _ { tcx.sess.span_err(ex.span, + "constant contains unimplemented expression type"); } + } +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index e054d359bb9bf..5e25d53e810a4 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5290,7 +5290,71 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id, fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { alt e.node { ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); } - _ { cx.sess.span_unimpl(e.span, "consts that's not a plain literal"); } + ast::expr_binary(b, e1, e2) { + let te1 = trans_const_expr(cx, e1); + let te2 = trans_const_expr(cx, e2); + /* Neither type is bottom, and we expect them to be unified already, + * so the following is safe. */ + let ty = ty::expr_ty(ccx_tcx(cx), e1); + let is_float = ty::type_is_fp(ccx_tcx(cx), ty); + let signed = ty::type_is_signed(ccx_tcx(cx), ty); + ret alt b { + ast::add. { + if is_float { llvm::LLVMConstFAdd(te1, te2) } + else { llvm::LLVMConstAdd(te1, te2) } + } + ast::sub. { + if is_float { llvm::LLVMConstFSub(te1, te2) } + else { llvm::LLVMConstSub(te1, te2) } + } + ast::mul. { + if is_float { llvm::LLVMConstFMul(te1, te2) } + else { llvm::LLVMConstMul(te1, te2) } + } + ast::div. { + if is_float { llvm::LLVMConstFDiv(te1, te2) } + else if signed { llvm::LLVMConstSDiv(te1, te2) } + else { llvm::LLVMConstUDiv(te1, te2) } + } + ast::rem. { + if is_float { llvm::LLVMConstFRem(te1, te2) } + else if signed { llvm::LLVMConstSRem(te1, te2) } + else { llvm::LLVMConstURem(te1, te2) } + } + ast::and. | + ast::or. { cx.sess.span_unimpl(e.span, "binop logic"); } + ast::bitxor. { llvm::LLVMConstXor(te1, te2) } + ast::bitand. { llvm::LLVMConstAnd(te1, te2) } + ast::bitor. { llvm::LLVMConstOr(te1, te2) } + ast::lsl. { llvm::LLVMConstShl(te1, te2) } + ast::lsr. { llvm::LLVMConstLShr(te1, te2) } + ast::asr. { llvm::LLVMConstAShr(te1, te2) } + ast::eq. | + ast::lt. | + ast::le. | + ast::ne. | + ast::ge. | + ast::gt. { cx.sess.span_unimpl(e.span, "binop comparator"); } + } + } + ast::expr_unary(u, e) { + let te = trans_const_expr(cx, e); + let ty = ty::expr_ty(ccx_tcx(cx), e); + let is_float = ty::type_is_fp(ccx_tcx(cx), ty); + ret alt u { + ast::box(_) | + ast::uniq(_) | + ast::deref. { cx.sess.span_bug(e.span, + "bad unop type in trans_const_expr"); } + ast::not. { llvm::LLVMConstNot(te) } + ast::neg. { + if is_float { llvm::LLVMConstFNeg(te) } + else { llvm::LLVMConstNeg(te) } + } + } + } + _ { cx.sess.span_bug(e.span, + "bad constant expression type in trans_const_expr"); } } } diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index b54610dd5c3a1..9215cbcb9c1bb 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -27,6 +27,7 @@ mod middle { mod typeck; mod fn_usage; mod check_alt; + mod check_const; mod mut; mod alias; mod kind; diff --git a/src/test/run-pass/const-contents.rs b/src/test/run-pass/const-contents.rs new file mode 100644 index 0000000000000..a8fd1378c9e66 --- /dev/null +++ b/src/test/run-pass/const-contents.rs @@ -0,0 +1,17 @@ +// Issue #570 + +const lsl : int = 1 << 2; +const add : int = 1 + 2; +const addf : float = 1.0f + 2.0f; +const not : int = !0; +const notb : bool = !true; +const neg : int = -(1); + +fn main() { + assert(lsl == 4); + assert(add == 3); + assert(addf == 3.0f); + assert(not == -1); + assert(notb == false); + assert(neg == -1); +}