summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-04-17 15:07:38 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-04-17 15:15:20 -0700
commit70a9ce626d5faeb9b5de54a9f44043ea46691e31 (patch)
treead82626104b7abc1ede25369b1314e46ba2886cf /src/rustc
parentfac7fcc1234aca0969a4a9c6eeddaf21a25b73fe (diff)
downloadrust-70a9ce626d5faeb9b5de54a9f44043ea46691e31.tar.gz
rust-70a9ce626d5faeb9b5de54a9f44043ea46691e31.zip
Implement slice-borrowing on estr-uniq and str values.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/infer.rs17
-rw-r--r--src/rustc/middle/trans/base.rs99
-rw-r--r--src/rustc/middle/trans/tvec.rs34
3 files changed, 86 insertions, 64 deletions
diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs
index 24130a56048..568a97947dc 100644
--- a/src/rustc/middle/infer.rs
+++ b/src/rustc/middle/infer.rs
@@ -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)
               }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 2a57766d66f..a049ae2fde3 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -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)
-      }
-
-      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)
-      }
-
-      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)
-      }
-    };
+    let (base, len) = tvec::get_base_and_len(bcx, v, base_ty);
 
-    #debug("trans_index: lim %s", val_str(bcx.ccx().tn, lim));
-    #debug("trans_index: body %s", val_str(bcx.ccx().tn, body));
+    #debug("trans_index: base %s", val_str(bcx.ccx().tn, base));
+    #debug("trans_index: len %s", val_str(bcx.ccx().tn, len));
 
-    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);
       }
 
       _ {
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index 50224c0d413..d2374b06167 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -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");