diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 9730c7e968d..13f3cf72f5f 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -3636,8 +3636,13 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { } ast::expr_lit(lit) { return trans_lit(bcx, e, *lit, dest); } ast::expr_vec(args, _) { - return tvec::trans_evec(bcx, args, ast::vstore_fixed(none), - e.id, dest); + return tvec::trans_evec(bcx, tvec::individual_evec(args), + ast::vstore_fixed(none), e.id, dest); + } + ast::expr_repeat(element, count_expr, _) { + let count = ty::eval_repeat_count(bcx.tcx(), count_expr, e.span); + return tvec::trans_evec(bcx, tvec::repeating_evec(element, count), + ast::vstore_fixed(none), e.id, dest); } ast::expr_binary(op, lhs, rhs) { return trans_binary(bcx, op, lhs, rhs, dest, e); diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs index 0f99fe9b2f7..f85ca19a4b6 100644 --- a/src/rustc/middle/trans/tvec.rs +++ b/src/rustc/middle/trans/tvec.rs @@ -5,7 +5,7 @@ import back::abi; import base::{call_memmove, INIT, copy_val, load_if_immediate, get_tydesc, sub_block, do_spill_noroot, - dest, bcx_icx, non_gc_box_cast}; + dest, bcx_icx, non_gc_box_cast, move_val, lval_owned}; import syntax::codemap::span; import shape::llsize_of; import build::*; @@ -118,18 +118,39 @@ fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> } else { bcx } } -fn trans_evec(bcx: block, args: ~[@ast::expr], +enum evec_elements { + individual_evec(~[@ast::expr]), + repeating_evec(@ast::expr, uint) +} + +fn trans_evec(bcx: block, elements: evec_elements, vst: ast::vstore, id: ast::node_id, dest: dest) -> block { let _icx = bcx.insn_ctxt(~"tvec::trans_evec"); let ccx = bcx.ccx(); let mut bcx = bcx; + + // Handle the ignored case. if dest == base::ignore { - for vec::each(args) |arg| { - bcx = base::trans_expr(bcx, arg, base::ignore); + match elements { + individual_evec(args) => { + for vec::each(args) |arg| { + bcx = base::trans_expr(bcx, arg, base::ignore); + } + } + repeating_evec(element, _) => { + bcx = base::trans_expr(bcx, element, base::ignore); + } } return bcx; } + // Figure out the number of elements we need. + let count; + match elements { + individual_evec(args) => count = args.len(), + repeating_evec(_, len) => count = len + } + let vec_ty = node_id_type(bcx, id); let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); let llunitty = type_of::type_of(ccx, unit_ty); @@ -151,13 +172,12 @@ fn trans_evec(bcx: block, args: ~[@ast::expr], {bcx: bcx, val: v, dataptr: v} } ast::vstore_slice(_) { - let n = vec::len(args); // Make a fake type to use for the cleanup let ty = ty::mk_evec(bcx.tcx(), {ty: unit_ty, mutbl: ast::m_mutbl}, - ty::vstore_fixed(n)); + ty::vstore_fixed(count)); - let n = C_uint(ccx, n); + let n = C_uint(ccx, count); let vp = base::arrayalloca(bcx, llunitty, n); add_clean(bcx, vp, ty); @@ -171,15 +191,13 @@ fn trans_evec(bcx: block, args: ~[@ast::expr], {bcx: bcx, val: p, dataptr: vp} } ast::vstore_uniq { - let {bcx, val} = alloc_vec(bcx, unit_ty, args.len(), - heap_exchange); + let {bcx, val} = alloc_vec(bcx, unit_ty, count, heap_exchange); add_clean_free(bcx, val, heap_exchange); let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val)); {bcx: bcx, val: val, dataptr: dataptr} } ast::vstore_box { - let {bcx, val} = alloc_vec(bcx, unit_ty, args.len(), - heap_shared); + let {bcx, val} = alloc_vec(bcx, unit_ty, count, heap_shared); add_clean_free(bcx, val, heap_shared); let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val)); {bcx: bcx, val: val, dataptr: dataptr} @@ -192,12 +210,38 @@ fn trans_evec(bcx: block, args: ~[@ast::expr], debug!{"trans_evec: v: %s, dataptr: %s", val_str(ccx.tn, val), val_str(ccx.tn, dataptr)}; - for vec::each(args) |e| { - let lleltptr = InBoundsGEP(bcx, dataptr, ~[C_uint(ccx, i)]); - bcx = base::trans_expr_save_in(bcx, e, lleltptr); - add_clean_temp_mem(bcx, lleltptr, unit_ty); - vec::push(temp_cleanups, lleltptr); - i += 1u; + match elements { + individual_evec(args) => { + for vec::each(args) |e| { + let lleltptr = InBoundsGEP(bcx, dataptr, ~[C_uint(ccx, i)]); + bcx = base::trans_expr_save_in(bcx, e, lleltptr); + add_clean_temp_mem(bcx, lleltptr, unit_ty); + vec::push(temp_cleanups, lleltptr); + i += 1u; + } + } + repeating_evec(e, len) => { + // We make temporary space in the hope that this will be + // friendlier to LLVM alias analysis. + let lltmpspace = base::alloca(bcx, llunitty); + bcx = base::trans_expr_save_in(bcx, e, lltmpspace); + add_clean_temp_mem(bcx, lltmpspace, unit_ty); + vec::push(temp_cleanups, lltmpspace); + for len.timesi |i| { + let lleltptr = InBoundsGEP(bcx, dataptr, ~[C_uint(ccx, i)]); + if i == len - 1 { + // Move the last one in. + bcx = move_val(bcx, INIT, lleltptr, + lval_owned(bcx, lltmpspace), unit_ty); + } else { + // Copy all but the last one in. + let llval = load_if_immediate(bcx, lltmpspace, unit_ty); + bcx = copy_val(bcx, INIT, lleltptr, llval, unit_ty); + } + add_clean_temp_mem(bcx, lleltptr, unit_ty); + vec::push(temp_cleanups, lleltptr); + } + } } for vec::each(temp_cleanups) |cln| { revoke_clean(bcx, cln); } @@ -219,13 +263,17 @@ fn trans_evec(bcx: block, args: ~[@ast::expr], fn trans_vstore(bcx: block, e: @ast::expr, v: ast::vstore, dest: dest) -> block { alt e.node { - ast::expr_lit(@{node: ast::lit_str(s), span: _}) { + ast::expr_lit(@{node: ast::lit_str(s), span: _}) => { return trans_estr(bcx, s, some(v), dest); } - ast::expr_vec(es, mutbl) { - return trans_evec(bcx, es, v, e.id, dest); + ast::expr_vec(es, mutbl) => { + return trans_evec(bcx, individual_evec(es), v, e.id, dest); } - _ { + ast::expr_repeat(element, count_expr, mutbl) => { + let count = ty::eval_repeat_count(bcx.tcx(), count_expr, e.span); + return trans_evec(bcx, repeating_evec(element, count), v, e.id, dest); + } + _ => { bcx.sess().span_bug(e.span, ~"vstore on non-sequence type"); } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 0d587e60af2..29dbccc43f5 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -169,6 +169,7 @@ export terr_proto_mismatch; export terr_ret_style_mismatch; export purity_to_str; export param_tys_in_type; +export eval_repeat_count; // Data types @@ -3170,6 +3171,26 @@ fn normalize_ty(cx: ctxt, t: t) -> t { return t_norm; } +// Returns the repeat count for a repeating vector expression. +fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint { + match const_eval::eval_const_expr(tcx, count_expr) { + const_eval::const_int(count) => return count as uint, + const_eval::const_uint(count) => return count as uint, + const_eval::const_float(count) => { + tcx.sess.span_err(span, + ~"expected signed or unsigned integer for \ + repeat count but found float"); + return count as uint; + } + const_eval::const_str(_) => { + tcx.sess.span_err(span, + ~"expected signed or unsigned integer for \ + repeat count but found string"); + return 0; + } + } +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index dd557f93b9f..1297a39c520 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1150,26 +1150,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, is_loop_body, some(fcx)); } - fn eval_repeat_count(fcx: @fn_ctxt, count_expr: @ast::expr, span: span) - -> uint { - let tcx = fcx.ccx.tcx; - match const_eval::eval_const_expr(tcx, count_expr) { - const_eval::const_int(count) => return count as uint, - const_eval::const_uint(count) => return count as uint, - const_eval::const_float(count) => { - tcx.sess.span_err(span, - ~"expected signed or unsigned integer for \ - repeat count but found float"); - return count as uint; - } - const_eval::const_str(_) => { - tcx.sess.span_err(span, - ~"expected signed or unsigned integer for \ - repeat count but found string"); - return 0; - } - } - } // Check field access expressions fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, @@ -1284,7 +1264,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, tt) } ast::expr_repeat(element, count_expr, mutbl) => { - let count = eval_repeat_count(fcx, count_expr, expr.span); + let count = ty::eval_repeat_count(tcx, count_expr, expr.span); fcx.write_ty(count_expr.id, ty::mk_uint(tcx)); let tt = ast_expr_vstore_to_vstore(fcx, ev, count, vst); let t: ty::t = fcx.infcx.next_ty_var(); @@ -1642,7 +1622,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, fcx.write_ty(id, typ); } ast::expr_repeat(element, count_expr, mutbl) { - let count = eval_repeat_count(fcx, count_expr, expr.span); + let count = ty::eval_repeat_count(tcx, count_expr, expr.span); fcx.write_ty(count_expr.id, ty::mk_uint(tcx)); let t: ty::t = fcx.infcx.next_ty_var(); bot |= check_expr_with(fcx, element, t); diff --git a/src/test/run-pass/repeated-vector-syntax.rs b/src/test/run-pass/repeated-vector-syntax.rs new file mode 100644 index 00000000000..e6b9e2b408a --- /dev/null +++ b/src/test/run-pass/repeated-vector-syntax.rs @@ -0,0 +1,7 @@ +fn main() { + let x = [ @[true], ..512 ]; + let y = [ 0, ..1 ]; + error!("%?", x); + error!("%?", y); +} +