Implement slice-borrowing on estr-uniq and str values.
This commit is contained in:
parent
fac7fcc123
commit
70a9ce626d
@ -810,12 +810,29 @@ impl assignment for infer_ctxt {
|
||||
let nr_b = ty::mk_uniq(self.tcx, mt_b);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_estr(vs_a),
|
||||
ty::ty_estr(ty::vstore_slice(r_b)))
|
||||
if is_borrowable(vs_a) {
|
||||
let nr_b = ty::mk_estr(self.tcx, vs_a);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_str,
|
||||
ty::ty_estr(ty::vstore_slice(r_b))) {
|
||||
let nr_b = ty::mk_str(self.tcx);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
}
|
||||
|
||||
(ty::ty_evec(mt_a, vs_a),
|
||||
ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
|
||||
if is_borrowable(vs_a) {
|
||||
let nr_b = ty::mk_evec(self.tcx, mt_b, vs_a);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_vec(mt_a),
|
||||
ty::ty_evec(mt_b, ty::vstore_slice(r_b))) {
|
||||
let nr_b = ty::mk_vec(self.tcx, mt_b);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
}
|
||||
_ {
|
||||
self.sub_tys(a, b)
|
||||
}
|
||||
|
@ -2257,6 +2257,7 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
|
||||
ret {bcx: bcx, val: val, kind: owned};
|
||||
}
|
||||
|
||||
|
||||
fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
|
||||
idx: @ast::expr) -> lval_result {
|
||||
let _icx = cx.insn_ctxt("trans_index");
|
||||
@ -2286,43 +2287,17 @@ fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
|
||||
let scaled_ix = Mul(bcx, ix_val, unit_sz);
|
||||
maybe_name_value(cx.ccx(), scaled_ix, "scaled_ix");
|
||||
|
||||
let (lim, body) = alt ty::get(base_ty).struct {
|
||||
ty::ty_estr(ty::vstore_fixed(n)) |
|
||||
ty::ty_evec(_, ty::vstore_fixed(n)) {
|
||||
// FIXME: support static bounds-check elimination
|
||||
// and/or error checking here.
|
||||
let lim = C_uint(bcx.ccx(), n);
|
||||
let body = GEPi(bcx, v, [0, 0]);
|
||||
(lim, body)
|
||||
}
|
||||
let (base, len) = tvec::get_base_and_len(bcx, v, base_ty);
|
||||
|
||||
ty::ty_estr(ty::vstore_slice(_)) |
|
||||
ty::ty_evec(_, ty::vstore_slice(_)) {
|
||||
let body = Load(bcx, GEPi(bcx, v, [0, abi::slice_elt_base]));
|
||||
let lim = Load(bcx, GEPi(bcx, v, [0, abi::slice_elt_len]));
|
||||
(lim, body)
|
||||
}
|
||||
#debug("trans_index: base %s", val_str(bcx.ccx().tn, base));
|
||||
#debug("trans_index: len %s", val_str(bcx.ccx().tn, len));
|
||||
|
||||
ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) {
|
||||
bcx.sess().unimpl(#fmt("unsupported evec/estr type trans_index"));
|
||||
}
|
||||
|
||||
_ {
|
||||
let lim = tvec::get_fill(bcx, v);
|
||||
let body = tvec::get_dataptr(bcx, v, type_of(ccx, unit_ty));
|
||||
(lim, body)
|
||||
}
|
||||
};
|
||||
|
||||
#debug("trans_index: lim %s", val_str(bcx.ccx().tn, lim));
|
||||
#debug("trans_index: body %s", val_str(bcx.ccx().tn, body));
|
||||
|
||||
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, lim);
|
||||
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
|
||||
let bcx = with_cond(bcx, bounds_check) {|bcx|
|
||||
// fail: bad bounds check.
|
||||
trans_fail(bcx, some(ex.span), "bounds check")
|
||||
};
|
||||
let elt = InBoundsGEP(bcx, body, [ix_val]);
|
||||
let elt = InBoundsGEP(bcx, base, [ix_val]);
|
||||
ret lval_owned(bcx, PointerCast(bcx, elt, T_ptr(llunitty)));
|
||||
}
|
||||
|
||||
@ -2543,6 +2518,7 @@ fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
|
||||
fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
||||
&temp_cleanups: [ValueRef], ret_flag: option<ValueRef>)
|
||||
-> result {
|
||||
#debug("+++ trans_arg_expr on %s", expr_to_str(e));
|
||||
let _icx = cx.insn_ctxt("trans_arg_expr");
|
||||
let ccx = cx.ccx();
|
||||
let e_ty = expr_ty(cx, e);
|
||||
@ -2563,6 +2539,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
||||
let lv = adapt_borrowed_value(lv, arg, e);
|
||||
let mut bcx = lv.bcx;
|
||||
let mut val = lv.val;
|
||||
#debug(" adapted value: %s", val_str(bcx.ccx().tn, val));
|
||||
let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
|
||||
if is_bot {
|
||||
// For values of type _|_, we generate an
|
||||
@ -2572,50 +2549,52 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
||||
val = llvm::LLVMGetUndef(lldestty);
|
||||
} else if arg_mode == ast::by_ref || arg_mode == ast::by_val {
|
||||
let mut copied = false;
|
||||
let imm = ty::type_is_immediate(e_ty);
|
||||
let imm = ty::type_is_immediate(arg.ty);
|
||||
if arg_mode == ast::by_ref && lv.kind != owned && imm {
|
||||
val = do_spill_noroot(bcx, val);
|
||||
copied = true;
|
||||
}
|
||||
if ccx.maps.copy_map.contains_key(e.id) && lv.kind != temporary {
|
||||
if !copied {
|
||||
let alloc = alloc_ty(bcx, e_ty);
|
||||
let alloc = alloc_ty(bcx, arg.ty);
|
||||
bcx = copy_val(bcx, INIT, alloc,
|
||||
load_if_immediate(bcx, val, e_ty), e_ty);
|
||||
load_if_immediate(bcx, val, arg.ty), arg.ty);
|
||||
val = alloc;
|
||||
} else { bcx = take_ty(bcx, val, e_ty); }
|
||||
add_clean(bcx, val, e_ty);
|
||||
} else { bcx = take_ty(bcx, val, arg.ty); }
|
||||
add_clean(bcx, val, arg.ty);
|
||||
}
|
||||
if arg_mode == ast::by_val && (lv.kind == owned || !imm) {
|
||||
val = Load(bcx, val);
|
||||
}
|
||||
} else if arg_mode == ast::by_copy || arg_mode == ast::by_move {
|
||||
let alloc = alloc_ty(bcx, e_ty);
|
||||
let alloc = alloc_ty(bcx, arg.ty);
|
||||
let move_out = arg_mode == ast::by_move ||
|
||||
ccx.maps.last_uses.contains_key(e.id);
|
||||
if lv.kind == temporary { revoke_clean(bcx, val); }
|
||||
if lv.kind == owned || !ty::type_is_immediate(e_ty) {
|
||||
memmove_ty(bcx, alloc, val, e_ty);
|
||||
if move_out && ty::type_needs_drop(ccx.tcx, e_ty) {
|
||||
bcx = zero_alloca(bcx, val, e_ty);
|
||||
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
|
||||
memmove_ty(bcx, alloc, val, arg.ty);
|
||||
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
||||
bcx = zero_alloca(bcx, val, arg.ty);
|
||||
}
|
||||
} else { Store(bcx, val, alloc); }
|
||||
val = alloc;
|
||||
if lv.kind != temporary && !move_out {
|
||||
bcx = take_ty(bcx, val, e_ty);
|
||||
bcx = take_ty(bcx, val, arg.ty);
|
||||
}
|
||||
|
||||
// In the event that failure occurs before the call actually
|
||||
// happens, have to cleanup this copy:
|
||||
add_clean_temp_mem(bcx, val, e_ty);
|
||||
add_clean_temp_mem(bcx, val, arg.ty);
|
||||
temp_cleanups += [val];
|
||||
} else if ty::type_is_immediate(e_ty) && lv.kind != owned {
|
||||
val = do_spill(bcx, val, e_ty);
|
||||
} else if ty::type_is_immediate(arg.ty) && lv.kind != owned {
|
||||
val = do_spill(bcx, val, arg.ty);
|
||||
}
|
||||
|
||||
if !is_bot && arg.ty != e_ty || ty::type_has_params(arg.ty) {
|
||||
#debug(" casting from %s", val_str(bcx.ccx().tn, val));
|
||||
val = PointerCast(bcx, val, lldestty);
|
||||
}
|
||||
#debug("--- trans_arg_expr passing %s", val_str(bcx.ccx().tn, val));
|
||||
ret rslt(bcx, val);
|
||||
}
|
||||
|
||||
@ -2642,25 +2621,17 @@ fn adapt_borrowed_value(lv: lval_result, _arg: ty::arg,
|
||||
ret lv; // no change needed at runtime (I think)
|
||||
}
|
||||
|
||||
ty::ty_estr(ty::vstore_box) |
|
||||
ty::ty_evec(_, ty::vstore_box) {
|
||||
bcx.tcx().sess.span_unimpl(
|
||||
e.span, #fmt["borrowing a value of type %s",
|
||||
ty_to_str(bcx.tcx(), e_ty)]);
|
||||
}
|
||||
|
||||
ty::ty_estr(ty::vstore_uniq) |
|
||||
ty::ty_evec(_, ty::vstore_uniq) {
|
||||
bcx.tcx().sess.span_unimpl(
|
||||
e.span, #fmt["borrowing a value of type %s",
|
||||
ty_to_str(bcx.tcx(), e_ty)]);
|
||||
}
|
||||
|
||||
ty::ty_estr(ty::vstore_fixed(_)) |
|
||||
ty::ty_evec(_, ty::vstore_fixed(_)) {
|
||||
bcx.tcx().sess.span_unimpl(
|
||||
e.span, #fmt["borrowing a value of type %s",
|
||||
ty_to_str(bcx.tcx(), e_ty)]);
|
||||
ty::ty_str | ty::ty_vec(_) |
|
||||
ty::ty_estr(_) |
|
||||
ty::ty_evec(_, _) {
|
||||
let ccx = bcx.ccx();
|
||||
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
|
||||
let llunit_ty = type_of(ccx, unit_ty);
|
||||
let (base, len) = tvec::get_base_and_len(bcx, lv.val, e_ty);
|
||||
let p = alloca(bcx, T_struct([T_ptr(llunit_ty), ccx.int_type]));
|
||||
Store(bcx, base, GEPi(bcx, p, [0, abi::slice_elt_base]));
|
||||
Store(bcx, len, GEPi(bcx, p, [0, abi::slice_elt_len]));
|
||||
ret lval_temp(bcx, p);
|
||||
}
|
||||
|
||||
_ {
|
||||
|
@ -145,6 +145,40 @@ fn trans_vstore(bcx: block, e: @ast::expr,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_base_and_len(cx: block, v: ValueRef, e_ty: ty::t)
|
||||
-> (ValueRef, ValueRef) {
|
||||
|
||||
let tcx = cx.ccx().tcx;
|
||||
let vec_ty = ty::type_autoderef(tcx, e_ty);
|
||||
let unit_ty = ty::sequence_element_type(tcx, vec_ty);
|
||||
let vstore = alt ty::get(vec_ty).struct {
|
||||
ty::ty_estr(vst) | ty::ty_evec(_, vst) { vst }
|
||||
_ { ty::vstore_uniq }
|
||||
};
|
||||
|
||||
alt vstore {
|
||||
ty::vstore_fixed(n) {
|
||||
let base = GEPi(cx, v, [0, 0]);
|
||||
let len = C_uint(cx.ccx(), n);
|
||||
(base, len)
|
||||
}
|
||||
ty::vstore_slice(_) {
|
||||
let base = Load(cx, GEPi(cx, v, [0, abi::slice_elt_base]));
|
||||
let len = Load(cx, GEPi(cx, v, [0, abi::slice_elt_len]));
|
||||
(base, len)
|
||||
}
|
||||
ty::vstore_uniq {
|
||||
let base = tvec::get_dataptr(cx, v,
|
||||
type_of::type_of(cx.ccx(), unit_ty));
|
||||
let len = tvec::get_fill(cx, v);
|
||||
(base, len)
|
||||
}
|
||||
ty::vstore_box {
|
||||
cx.ccx().sess.unimpl("unhandled tvec::get_base_and_len");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_estr(bcx: block, s: str, vstore: ast::vstore,
|
||||
dest: dest) -> block {
|
||||
let _icx = bcx.insn_ctxt("tvec::trans_estr");
|
||||
|
9
src/test/run-pass/regions-borrow-estr-uniq.rs
Normal file
9
src/test/run-pass/regions-borrow-estr-uniq.rs
Normal file
@ -0,0 +1,9 @@
|
||||
fn foo(x: str/&) -> u8 {
|
||||
x[0]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = "hello"/~;
|
||||
let r = foo(p);
|
||||
assert r == 'h' as u8;
|
||||
}
|
Loading…
Reference in New Issue
Block a user