2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* A `Datum` contains all the information you need to describe the LLVM
|
|
|
|
* translation of a Rust value. It describes where the value is stored,
|
|
|
|
* what Rust type the value has, whether it is addressed by reference,
|
|
|
|
* and so forth.
|
|
|
|
*
|
|
|
|
* The idea of a datum is that, to the extent possible, you should not
|
|
|
|
* care about these details, but rather use the methods on the Datum
|
|
|
|
* type to "do what you want to do". For example, you can simply call
|
|
|
|
* `copy_to()` or `move_to()` to copy or move the value into a new
|
|
|
|
* home.
|
|
|
|
*
|
|
|
|
* # Datum location
|
|
|
|
*
|
|
|
|
* The primary two fields of a datum are the `val` and the `mode`.
|
|
|
|
* The `val` is an LLVM value ref. It may either *be the value* that
|
|
|
|
* is being tracked, or it may be a *pointer to the value being
|
|
|
|
* tracked*. This is specified in the `mode` field, which can either
|
|
|
|
* be `ByValue` or `ByRef`, respectively. The (Rust) type of the
|
|
|
|
* value stored in the datum is indicated in the field `ty`.
|
|
|
|
*
|
|
|
|
* Generally speaking, you probably do not want to access the `val` field
|
|
|
|
* unless you know what mode the value is in. Intead you should use one
|
|
|
|
* of the following accessors:
|
|
|
|
*
|
|
|
|
* - `to_value_llval()` converts to by-value
|
|
|
|
* - `to_ref_llval()` converts to by-ref, allocating a stack slot if necessary
|
|
|
|
* - `to_appropriate_llval()` converts to by-value if this is an
|
|
|
|
* immediate type, by-ref otherwise. This is particularly
|
|
|
|
* convenient for interfacing with the various code floating around
|
|
|
|
* that predates datums.
|
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* # Datum cleanup styles
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* Each datum carries with it an idea of how its value will be cleaned
|
|
|
|
* up. This is important after a move, because we need to know how to
|
|
|
|
* cancel the cleanup (since the value has been moved and therefore does
|
|
|
|
* not need to be freed). There are two options:
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* 1. `RevokeClean`: To cancel the cleanup, we invoke `revoke_clean()`.
|
|
|
|
* This is used for temporary rvalues.
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* 2. `ZeroMem`: To cancel the cleanup, we zero out the memory where
|
|
|
|
* the value resides. This is used for lvalues.
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* # Copying, moving, and storing
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* There are three methods for moving the value into a new
|
|
|
|
* location:
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* - `copy_to()` will copy the value into a new location, meaning that
|
|
|
|
* the value is first mem-copied and then the new location is "taken"
|
|
|
|
* via the take glue, in effect creating a deep clone.
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* - `move_to()` will copy the value, meaning that the value is mem-copied
|
|
|
|
* into its new home and then the cleanup on the this datum is revoked.
|
|
|
|
* This is a "shallow" clone. After `move_to()`, the current datum
|
|
|
|
* is invalid and should no longer be used.
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
2013-01-10 12:59:58 -06:00
|
|
|
* - `store_to()` either performs a copy or a move by consulting the
|
|
|
|
* moves_map computed by `middle::moves`.
|
2012-08-28 17:54:45 -05:00
|
|
|
*
|
|
|
|
* # Scratch datum
|
|
|
|
*
|
|
|
|
* Sometimes you just need some temporary scratch space. The
|
|
|
|
* `scratch_datum()` function will yield you up a by-ref datum that
|
|
|
|
* points into the stack. It's your responsibility to ensure that
|
|
|
|
* whatever you put in there gets cleaned up etc.
|
|
|
|
*
|
|
|
|
* # Other actions
|
|
|
|
*
|
|
|
|
* There are various other helper methods on Datum, such as `deref()`,
|
|
|
|
* `get_base_and_len()` and so forth. These are documented on the
|
|
|
|
* methods themselves. Most are only suitable for some types of
|
|
|
|
* values. */
|
|
|
|
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
2013-01-07 16:16:52 -06:00
|
|
|
|
2013-02-25 13:11:21 -06:00
|
|
|
use lib;
|
2012-08-28 17:54:45 -05:00
|
|
|
use lib::llvm::ValueRef;
|
2013-01-25 18:57:39 -06:00
|
|
|
use middle::borrowck::{RootInfo, root_map_key};
|
2013-02-24 16:01:43 -06:00
|
|
|
use middle::trans::adt;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::base::*;
|
|
|
|
use middle::trans::build::*;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::callee;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::common::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::common;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::expr;
|
|
|
|
use middle::trans::glue;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::tvec;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::type_of;
|
|
|
|
use middle::ty;
|
2012-08-28 17:54:45 -05:00
|
|
|
use util::common::indenter;
|
2012-12-13 15:05:22 -06:00
|
|
|
use util::ppaux::ty_to_str;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::cmp;
|
2013-02-25 13:11:21 -06:00
|
|
|
use core::to_bytes;
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::uint;
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast;
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::parse::token::special_idents;
|
|
|
|
|
2013-02-14 23:17:26 -06:00
|
|
|
#[deriving_eq]
|
2013-01-29 19:57:02 -06:00
|
|
|
pub enum CopyAction {
|
2012-08-28 17:54:45 -05:00
|
|
|
INIT,
|
|
|
|
DROP_EXISTING
|
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub struct Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
/// The llvm value. This is either a pointer to the Rust value or
|
|
|
|
/// the value itself, depending on `mode` below.
|
2012-09-07 16:50:47 -05:00
|
|
|
val: ValueRef,
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
/// The rust type of the value.
|
2012-09-07 16:50:47 -05:00
|
|
|
ty: ty::t,
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
/// Indicates whether this is by-ref or by-value.
|
2012-09-07 16:50:47 -05:00
|
|
|
mode: DatumMode,
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
/// How did this value originate? This is particularly important
|
|
|
|
/// if the value is MOVED or prematurely DROPPED, because it
|
|
|
|
/// describes how to cancel the cleanup that was scheduled before.
|
2013-01-10 12:59:58 -06:00
|
|
|
/// See the def'n of the `DatumCleanup` type.
|
|
|
|
source: DatumCleanup
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub struct DatumBlock {
|
2012-09-07 16:50:47 -05:00
|
|
|
bcx: block,
|
|
|
|
datum: Datum,
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub enum DatumMode {
|
2012-08-28 17:54:45 -05:00
|
|
|
/// `val` is a pointer to the actual value (and thus has type *T)
|
|
|
|
ByRef,
|
|
|
|
|
|
|
|
/// `val` is the actual value (*only used for immediates* like ints, ptrs)
|
|
|
|
ByValue,
|
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub impl DatumMode {
|
2013-02-22 00:41:37 -06:00
|
|
|
fn is_by_ref(&self) -> bool {
|
|
|
|
match *self { ByRef => true, ByValue => false }
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn is_by_value(&self) -> bool {
|
|
|
|
match *self { ByRef => false, ByValue => true }
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-26 19:12:00 -06:00
|
|
|
impl cmp::Eq for DatumMode {
|
2012-11-14 20:59:30 -06:00
|
|
|
pure fn eq(&self, other: &DatumMode) -> bool {
|
|
|
|
(*self) as uint == (*other as uint)
|
|
|
|
}
|
|
|
|
pure fn ne(&self, other: &DatumMode) -> bool { !(*self).eq(other) }
|
2012-09-20 14:29:15 -05:00
|
|
|
}
|
|
|
|
|
2013-02-26 19:12:00 -06:00
|
|
|
impl to_bytes::IterBytes for DatumMode {
|
2012-11-28 13:36:04 -06:00
|
|
|
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
|
|
|
(*self as uint).iter_bytes(lsb0, f)
|
|
|
|
}
|
|
|
|
}
|
2012-09-20 14:29:15 -05:00
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
/// See `Datum cleanup styles` section at the head of this module.
|
|
|
|
#[deriving_eq]
|
|
|
|
pub enum DatumCleanup {
|
|
|
|
RevokeClean,
|
|
|
|
ZeroMem
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub fn immediate_rvalue(val: ValueRef, ty: ty::t) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
return Datum {val: val, ty: ty,
|
2013-01-10 12:59:58 -06:00
|
|
|
mode: ByValue, source: RevokeClean};
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub fn immediate_rvalue_bcx(bcx: block,
|
|
|
|
val: ValueRef,
|
|
|
|
ty: ty::t)
|
|
|
|
-> DatumBlock {
|
2012-08-28 17:54:45 -05:00
|
|
|
return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)};
|
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Allocates temporary space on the stack using alloca() and
|
2012-09-11 23:25:01 -05:00
|
|
|
* returns a by-ref Datum pointing to it. If `zero` is true, the
|
|
|
|
* space will be zeroed when it is allocated; this is normally not
|
|
|
|
* necessary, but in the case of automatic rooting in match
|
|
|
|
* statements it is possible to have temporaries that may not get
|
|
|
|
* initialized if a certain arm is not taken, so we must zero
|
|
|
|
* them. You must arrange any cleanups etc yourself! */
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-09-07 11:17:27 -05:00
|
|
|
let llty = type_of::type_of(bcx.ccx(), ty);
|
|
|
|
let scratch = alloca_maybe_zeroed(bcx, llty, zero);
|
2013-01-10 12:59:58 -06:00
|
|
|
Datum { val: scratch, ty: ty, mode: ByRef, source: RevokeClean }
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub fn appropriate_mode(ty: ty::t) -> DatumMode {
|
2012-09-20 14:29:15 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Indicates the "appropriate" mode for this value,
|
|
|
|
* which is either by ref or by value, depending
|
2012-09-26 21:40:05 -05:00
|
|
|
* on whether type is immediate or not. */
|
2012-09-20 14:29:15 -05:00
|
|
|
|
|
|
|
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
|
|
|
|
ByValue
|
|
|
|
} else if ty::type_is_immediate(ty) {
|
|
|
|
ByValue
|
|
|
|
} else {
|
|
|
|
ByRef
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub impl Datum {
|
2013-02-22 00:41:37 -06:00
|
|
|
fn store_to(&self, bcx: block, id: ast::node_id,
|
2013-01-10 12:59:58 -06:00
|
|
|
action: CopyAction, dst: ValueRef) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Stores this value into its final home. This moves if
|
2013-01-10 12:59:58 -06:00
|
|
|
* `id` is located in the move table, but copies otherwise.
|
|
|
|
*/
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-02-08 16:08:02 -06:00
|
|
|
if bcx.ccx().maps.moves_map.contains_key(&id) {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.move_to(bcx, action, dst)
|
|
|
|
} else {
|
|
|
|
self.copy_to(bcx, action, dst)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn store_to_dest(&self, bcx: block, id: ast::node_id,
|
2013-01-10 12:59:58 -06:00
|
|
|
dest: expr::Dest) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
match dest {
|
|
|
|
expr::Ignore => {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
expr::SaveIn(addr) => {
|
2013-01-10 12:59:58 -06:00
|
|
|
return self.store_to(bcx, id, INIT, addr);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn store_to_datum(&self, bcx: block, id: ast::node_id,
|
2013-01-10 12:59:58 -06:00
|
|
|
action: CopyAction, datum: Datum) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("store_to_datum(self=%s, action=%?, datum=%s)",
|
|
|
|
self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx()));
|
|
|
|
assert datum.mode.is_by_ref();
|
2013-01-10 12:59:58 -06:00
|
|
|
self.store_to(bcx, id, action, datum.val)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
|
|
|
|
-> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
assert datum.mode.is_by_ref();
|
|
|
|
self.move_to(bcx, action, datum.val)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn copy_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
|
|
|
|
-> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
assert datum.mode.is_by_ref();
|
|
|
|
self.copy_to(bcx, action, datum.val)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn copy_to(&self, bcx: block, action: CopyAction, dst: ValueRef)
|
|
|
|
-> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Copies the value into `dst`, which should be a pointer to a
|
|
|
|
* memory location suitable for `self.ty`. You PROBABLY want
|
|
|
|
* `store_to()` instead, which will move if possible but copy if
|
|
|
|
* neccessary. */
|
|
|
|
|
|
|
|
let _icx = bcx.insn_ctxt("copy_to");
|
|
|
|
|
2012-09-07 14:06:42 -05:00
|
|
|
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("copy_to(self=%s, action=%?, dst=%s)",
|
|
|
|
self.to_str(bcx.ccx()), action, bcx.val_str(dst));
|
|
|
|
|
|
|
|
// Watch out for the case where we are writing the copying the
|
|
|
|
// value into the same location we read it out from. We want
|
|
|
|
// to avoid the case where we drop the existing value, which
|
|
|
|
// frees it, and then overwrite it with itself (which has been
|
|
|
|
// freed).
|
|
|
|
if action == DROP_EXISTING &&
|
|
|
|
ty::type_needs_drop(bcx.tcx(), self.ty)
|
|
|
|
{
|
|
|
|
match self.mode {
|
|
|
|
ByRef => {
|
|
|
|
let cast = PointerCast(bcx, dst, val_ty(self.val));
|
|
|
|
let cmp = ICmp(bcx, lib::llvm::IntNE, cast, self.val);
|
|
|
|
do with_cond(bcx, cmp) |bcx| {
|
|
|
|
self.copy_to_no_check(bcx, action, dst)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ByValue => {
|
|
|
|
self.copy_to_no_check(bcx, action, dst)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.copy_to_no_check(bcx, action, dst)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn copy_to_no_check(&self, bcx: block, action: CopyAction,
|
2012-08-28 17:54:45 -05:00
|
|
|
dst: ValueRef) -> block
|
|
|
|
{
|
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* A helper for `copy_to()` which does not check to see if we
|
|
|
|
* are copying to/from the same value. */
|
|
|
|
|
|
|
|
let _icx = bcx.insn_ctxt("copy_to_no_check");
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
|
|
|
if action == DROP_EXISTING {
|
|
|
|
bcx = glue::drop_ty(bcx, dst, self.ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.mode {
|
|
|
|
ByValue => {
|
|
|
|
Store(bcx, self.val, dst);
|
|
|
|
}
|
|
|
|
ByRef => {
|
2013-02-25 13:11:21 -06:00
|
|
|
memcpy_ty(bcx, dst, self.val, self.ty);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return glue::take_ty(bcx, dst, self.ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This works like copy_val, except that it deinitializes the source.
|
|
|
|
// Since it needs to zero out the source, src also needs to be an lval.
|
|
|
|
//
|
2013-02-22 00:41:37 -06:00
|
|
|
fn move_to(&self, bcx: block, action: CopyAction, dst: ValueRef)
|
|
|
|
-> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
let _icx = bcx.insn_ctxt("move_to");
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
|
|
|
debug!("move_to(self=%s, action=%?, dst=%s)",
|
|
|
|
self.to_str(bcx.ccx()), action, bcx.val_str(dst));
|
|
|
|
|
|
|
|
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
|
|
|
if action == DROP_EXISTING {
|
|
|
|
bcx = glue::drop_ty(bcx, dst, self.ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.mode {
|
|
|
|
ByRef => {
|
2013-02-25 13:11:21 -06:00
|
|
|
memcpy_ty(bcx, dst, self.val, self.ty);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
ByValue => {
|
|
|
|
Store(bcx, self.val, dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.cancel_clean(bcx);
|
|
|
|
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn add_clean(&self, bcx: block) {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Schedules this datum for cleanup in `bcx`. The datum
|
|
|
|
* must be an rvalue. */
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
assert self.source == RevokeClean;
|
2012-08-28 17:54:45 -05:00
|
|
|
match self.mode {
|
|
|
|
ByValue => {
|
|
|
|
add_clean_temp_immediate(bcx, self.val, self.ty);
|
|
|
|
}
|
|
|
|
ByRef => {
|
|
|
|
add_clean_temp_mem(bcx, self.val, self.ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn cancel_clean(&self, bcx: block) {
|
2012-08-28 17:54:45 -05:00
|
|
|
if ty::type_needs_drop(bcx.tcx(), self.ty) {
|
|
|
|
match self.source {
|
2013-01-10 12:59:58 -06:00
|
|
|
RevokeClean => {
|
2012-08-28 17:54:45 -05:00
|
|
|
revoke_clean(bcx, self.val);
|
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
ZeroMem => {
|
2012-08-28 17:54:45 -05:00
|
|
|
// Lvalues which potentially need to be dropped
|
|
|
|
// must be passed by ref, so that we can zero them
|
|
|
|
// out.
|
|
|
|
assert self.mode.is_by_ref();
|
|
|
|
zero_mem(bcx, self.val, self.ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_str(&self, ccx: &CrateContext) -> ~str {
|
2012-08-28 17:54:45 -05:00
|
|
|
fmt!("Datum { val=%s, ty=%s, mode=%?, source=%? }",
|
|
|
|
val_str(ccx.tn, self.val),
|
|
|
|
ty_to_str(ccx.tcx, self.ty),
|
|
|
|
self.mode,
|
|
|
|
self.source)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_value_datum(&self, bcx: block) -> Datum {
|
2012-09-06 17:21:42 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Yields a by-ref form of this datum. This may involve
|
|
|
|
* creation of a temporary stack slot. The value returned by
|
|
|
|
* this function is not separately rooted from this datum, so
|
|
|
|
* it will not live longer than the current datum. */
|
|
|
|
|
|
|
|
match self.mode {
|
2013-02-22 00:41:37 -06:00
|
|
|
ByValue => *self,
|
2012-09-06 17:21:42 -05:00
|
|
|
ByRef => {
|
|
|
|
Datum {val: self.to_value_llval(bcx), mode: ByValue,
|
2013-01-10 12:59:58 -06:00
|
|
|
ty: self.ty, source: RevokeClean}
|
2012-09-06 17:21:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_value_llval(&self, bcx: block) -> ValueRef {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Yields the value itself. */
|
|
|
|
|
2012-09-06 17:21:42 -05:00
|
|
|
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
|
|
|
|
C_nil()
|
|
|
|
} else {
|
|
|
|
match self.mode {
|
|
|
|
ByValue => self.val,
|
2013-02-19 18:15:03 -06:00
|
|
|
ByRef => {
|
|
|
|
if ty::type_is_bool(self.ty) {
|
|
|
|
LoadRangeAssert(bcx, self.val, 0, 2, lib::llvm::True)
|
|
|
|
} else {
|
|
|
|
Load(bcx, self.val)
|
|
|
|
}
|
|
|
|
}
|
2012-09-06 17:21:42 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_ref_datum(&self, bcx: block) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Yields a by-ref form of this datum. This may involve
|
|
|
|
* creation of a temporary stack slot. The value returned by
|
|
|
|
* this function is not separately rooted from this datum, so
|
|
|
|
* it will not live longer than the current datum. */
|
|
|
|
|
|
|
|
match self.mode {
|
2013-02-22 00:41:37 -06:00
|
|
|
ByRef => *self,
|
2012-08-28 17:54:45 -05:00
|
|
|
ByValue => {
|
|
|
|
Datum {val: self.to_ref_llval(bcx), mode: ByRef,
|
2013-01-10 12:59:58 -06:00
|
|
|
ty: self.ty, source: RevokeClean}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_ref_llval(&self, bcx: block) -> ValueRef {
|
2012-08-28 17:54:45 -05:00
|
|
|
match self.mode {
|
|
|
|
ByRef => self.val,
|
|
|
|
ByValue => {
|
2012-09-06 17:21:42 -05:00
|
|
|
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
|
|
|
|
C_null(T_ptr(type_of::type_of(bcx.ccx(), self.ty)))
|
|
|
|
} else {
|
|
|
|
let slot = alloc_ty(bcx, self.ty);
|
|
|
|
Store(bcx, self.val, slot);
|
|
|
|
slot
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn appropriate_mode(&self) -> DatumMode {
|
2012-09-20 14:29:15 -05:00
|
|
|
/*! See the `appropriate_mode()` function */
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-09-20 14:29:15 -05:00
|
|
|
appropriate_mode(self.ty)
|
2012-09-06 17:21:42 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_appropriate_llval(&self, bcx: block) -> ValueRef {
|
2012-09-06 17:21:42 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Yields an llvalue with the `appropriate_mode()`. */
|
|
|
|
|
|
|
|
match self.appropriate_mode() {
|
|
|
|
ByValue => self.to_value_llval(bcx),
|
|
|
|
ByRef => self.to_ref_llval(bcx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_appropriate_datum(&self, bcx: block) -> Datum {
|
2012-09-06 17:21:42 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Yields a datum with the `appropriate_mode()`. */
|
|
|
|
|
|
|
|
match self.appropriate_mode() {
|
|
|
|
ByValue => self.to_value_datum(bcx),
|
|
|
|
ByRef => self.to_ref_datum(bcx)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-24 14:42:39 -06:00
|
|
|
fn get_element(&self, bcx: block,
|
|
|
|
ty: ty::t,
|
|
|
|
source: DatumCleanup,
|
|
|
|
gep: fn(ValueRef) -> ValueRef) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
let base_val = self.to_ref_llval(bcx);
|
|
|
|
Datum {
|
2013-02-24 14:42:39 -06:00
|
|
|
val: gep(base_val),
|
2012-08-28 17:54:45 -05:00
|
|
|
mode: ByRef,
|
|
|
|
ty: ty,
|
2012-12-04 17:38:04 -06:00
|
|
|
source: source
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn root(&self, bcx: block, root_info: RootInfo) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* In some cases, borrowck will decide that an @T/@[]/@str
|
|
|
|
* value must be rooted for the program to be safe. In that
|
|
|
|
* case, we will call this function, which will stash a copy
|
|
|
|
* away until we exit the scope `scope_id`. */
|
|
|
|
|
2013-01-11 23:01:42 -06:00
|
|
|
debug!("root(scope_id=%?, freezes=%?, self=%?)",
|
|
|
|
root_info.scope, root_info.freezes, self.to_str(bcx.ccx()));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
if bcx.sess().trace() {
|
|
|
|
trans_trace(
|
|
|
|
bcx, None,
|
2013-02-20 18:41:21 -06:00
|
|
|
@fmt!("preserving until end of scope %d",
|
2013-02-18 14:36:30 -06:00
|
|
|
root_info.scope));
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let scratch = scratch_datum(bcx, self.ty, true);
|
|
|
|
self.copy_to_datum(bcx, INIT, scratch);
|
2013-02-25 13:11:21 -06:00
|
|
|
add_root_cleanup(bcx, root_info, scratch.val, scratch.ty);
|
2013-01-11 23:01:42 -06:00
|
|
|
|
|
|
|
// If we need to freeze the box, do that now.
|
|
|
|
if root_info.freezes {
|
2013-02-27 20:34:04 -06:00
|
|
|
callee::trans_lang_call(
|
2013-01-11 23:01:42 -06:00
|
|
|
bcx,
|
|
|
|
bcx.tcx().lang_items.borrow_as_imm_fn(),
|
|
|
|
~[
|
|
|
|
Load(bcx,
|
|
|
|
PointerCast(bcx,
|
|
|
|
scratch.val,
|
|
|
|
T_ptr(T_ptr(T_i8()))))
|
|
|
|
],
|
|
|
|
expr::Ignore)
|
|
|
|
} else {
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn perform_write_guard(&self, bcx: block) -> block {
|
2013-01-11 23:01:42 -06:00
|
|
|
// Create scratch space, but do not root it.
|
|
|
|
let llval = match self.mode {
|
|
|
|
ByValue => self.val,
|
|
|
|
ByRef => Load(bcx, self.val),
|
|
|
|
};
|
|
|
|
|
2013-02-27 20:34:04 -06:00
|
|
|
callee::trans_lang_call(
|
2013-01-11 23:01:42 -06:00
|
|
|
bcx,
|
|
|
|
bcx.tcx().lang_items.check_not_borrowed_fn(),
|
|
|
|
~[ PointerCast(bcx, llval, T_ptr(T_i8())) ],
|
|
|
|
expr::Ignore)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn drop_val(&self, bcx: block) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
if !ty::type_needs_drop(bcx.tcx(), self.ty) {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
|
|
|
return match self.mode {
|
|
|
|
ByRef => glue::drop_ty(bcx, self.val, self.ty),
|
|
|
|
ByValue => glue::drop_ty_immediate(bcx, self.val, self.ty)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn box_body(&self, bcx: block) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* This datum must represent an @T or ~T box. Returns a new
|
|
|
|
* by-ref datum of type T, pointing at the contents. */
|
|
|
|
|
2012-09-11 18:20:31 -05:00
|
|
|
let content_ty = match ty::get(self.ty).sty {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_box(mt) | ty::ty_uniq(mt) => mt.ty,
|
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.bug(fmt!(
|
|
|
|
"box_body() invoked on non-box type %s",
|
|
|
|
ty_to_str(bcx.tcx(), self.ty)));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let ptr = self.to_value_llval(bcx);
|
|
|
|
let body = opaque_box_body(bcx, content_ty, ptr);
|
2013-01-10 12:59:58 -06:00
|
|
|
Datum {val: body, ty: content_ty, mode: ByRef, source: ZeroMem}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_rptr(&self, bcx: block) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Returns a new datum of region-pointer type containing the
|
|
|
|
// the same ptr as this datum (after converting to by-ref
|
|
|
|
// using `to_ref_llval()`).
|
|
|
|
|
|
|
|
// Convert to ref, yielding lltype *T. Then create a Rust
|
|
|
|
// type &static/T (which translates to *T). Construct new
|
|
|
|
// result (which will be by-value). Note that it is not
|
|
|
|
// significant *which* region we pick here.
|
|
|
|
let llval = self.to_ref_llval(bcx);
|
|
|
|
let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::re_static,
|
|
|
|
self.ty);
|
|
|
|
Datum {val: llval, ty: rptr_ty,
|
2013-01-10 12:59:58 -06:00
|
|
|
mode: ByValue, source: RevokeClean}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn try_deref(&self,
|
2012-08-28 17:54:45 -05:00
|
|
|
bcx: block, // block wherein to generate insn's
|
|
|
|
expr_id: ast::node_id, // id of expr being deref'd
|
|
|
|
derefs: uint, // number of times deref'd already
|
|
|
|
is_auto: bool) // if true, only deref if auto-derefable
|
2013-01-11 23:01:42 -06:00
|
|
|
-> (Option<Datum>, block)
|
2012-08-28 17:54:45 -05:00
|
|
|
{
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
|
|
|
debug!("try_deref(expr_id=%d, derefs=%?, is_auto=%b, self=%?)",
|
|
|
|
expr_id, derefs, is_auto, self.to_str(bcx.ccx()));
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
// root the autoderef'd value, if necessary:
|
|
|
|
//
|
|
|
|
// (Note: root'd values are always boxes)
|
2013-01-25 18:57:39 -06:00
|
|
|
let key = root_map_key { id: expr_id, derefs: derefs };
|
2013-02-05 21:41:45 -06:00
|
|
|
let bcx = match ccx.maps.root_map.find(&key) {
|
2013-01-11 23:01:42 -06:00
|
|
|
None => bcx,
|
|
|
|
Some(root_info) => self.root(bcx, root_info)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Perform the write guard, if necessary.
|
|
|
|
//
|
|
|
|
// (Note: write-guarded values are always boxes)
|
2013-02-05 21:41:45 -06:00
|
|
|
let bcx = match ccx.maps.write_guard_map.find(&key) {
|
2013-01-11 23:01:42 -06:00
|
|
|
None => bcx,
|
|
|
|
Some(_) => self.perform_write_guard(bcx)
|
|
|
|
};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(self.ty).sty {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_box(_) | ty::ty_uniq(_) => {
|
2013-01-11 23:01:42 -06:00
|
|
|
return (Some(self.box_body(bcx)), bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
ty::ty_ptr(mt) => {
|
|
|
|
if is_auto { // unsafe ptrs are not AUTO-derefable
|
2013-01-11 23:01:42 -06:00
|
|
|
return (None, bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
} else {
|
2013-02-22 00:41:37 -06:00
|
|
|
return (Some(deref_ptr(bcx, self, mt.ty)), bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::ty_rptr(_, mt) => {
|
2013-02-22 00:41:37 -06:00
|
|
|
return (Some(deref_ptr(bcx, self, mt.ty)), bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
ty::ty_enum(did, ref substs) => {
|
|
|
|
// Check whether this enum is a newtype enum:
|
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2012-10-27 19:16:00 -05:00
|
|
|
if (*variants).len() != 1 || variants[0].args.len() != 1 {
|
2013-01-11 23:01:42 -06:00
|
|
|
return (None, bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-24 16:01:43 -06:00
|
|
|
let repr = adt::represent_type(ccx, self.ty);
|
2013-02-25 03:49:21 -06:00
|
|
|
assert adt::is_newtypeish(repr);
|
2012-08-28 17:54:45 -05:00
|
|
|
let ty = ty::subst(ccx.tcx, substs, variants[0].args[0]);
|
|
|
|
return match self.mode {
|
|
|
|
ByRef => {
|
|
|
|
// Recast lv.val as a pointer to the newtype
|
|
|
|
// rather than a ptr to the enum type.
|
2013-01-11 23:01:42 -06:00
|
|
|
(
|
|
|
|
Some(Datum {
|
2013-03-02 18:08:49 -06:00
|
|
|
val: adt::trans_field_ptr(bcx, repr, self.val,
|
2013-02-24 16:01:43 -06:00
|
|
|
0, 0),
|
2013-01-11 23:01:42 -06:00
|
|
|
ty: ty,
|
|
|
|
mode: ByRef,
|
2013-01-10 12:59:58 -06:00
|
|
|
source: ZeroMem
|
2013-01-11 23:01:42 -06:00
|
|
|
}),
|
|
|
|
bcx
|
|
|
|
)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
ByValue => {
|
|
|
|
// Actually, this case cannot happen right
|
|
|
|
// now, because enums are never immediate.
|
|
|
|
// But in principle newtype'd immediate
|
|
|
|
// values should be immediate, and in that
|
|
|
|
// case the * would be a no-op except for
|
|
|
|
// changing the type, so I am putting this
|
|
|
|
// code in place here to do the right
|
|
|
|
// thing if this change ever goes through.
|
|
|
|
assert ty::type_is_immediate(ty);
|
2013-02-22 00:41:37 -06:00
|
|
|
(Some(Datum {ty: ty, ..*self}), bcx)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2012-12-10 15:47:54 -06:00
|
|
|
ty::ty_struct(did, ref substs) => {
|
2012-10-30 20:31:47 -05:00
|
|
|
// Check whether this struct is a newtype struct.
|
2012-12-10 15:47:54 -06:00
|
|
|
let fields = ty::struct_fields(ccx.tcx, did, substs);
|
2012-10-30 20:31:47 -05:00
|
|
|
if fields.len() != 1 || fields[0].ident !=
|
2012-12-23 16:41:37 -06:00
|
|
|
special_idents::unnamed_field {
|
2013-01-11 23:01:42 -06:00
|
|
|
return (None, bcx);
|
2012-10-30 20:31:47 -05:00
|
|
|
}
|
|
|
|
|
2013-02-24 16:01:43 -06:00
|
|
|
let repr = adt::represent_type(ccx, self.ty);
|
2013-02-25 03:49:21 -06:00
|
|
|
assert adt::is_newtypeish(repr);
|
2012-10-30 20:31:47 -05:00
|
|
|
let ty = fields[0].mt.ty;
|
|
|
|
return match self.mode {
|
|
|
|
ByRef => {
|
|
|
|
// Recast lv.val as a pointer to the newtype rather
|
|
|
|
// than a pointer to the struct type.
|
|
|
|
// XXX: This isn't correct for structs with
|
|
|
|
// destructors.
|
2013-01-11 23:01:42 -06:00
|
|
|
(
|
|
|
|
Some(Datum {
|
2013-03-02 18:08:49 -06:00
|
|
|
val: adt::trans_field_ptr(bcx, repr, self.val,
|
2013-02-24 16:01:43 -06:00
|
|
|
0, 0),
|
2013-01-11 23:01:42 -06:00
|
|
|
ty: ty,
|
|
|
|
mode: ByRef,
|
2013-01-10 12:59:58 -06:00
|
|
|
source: ZeroMem
|
2013-01-11 23:01:42 -06:00
|
|
|
}),
|
|
|
|
bcx
|
|
|
|
)
|
2012-10-30 20:31:47 -05:00
|
|
|
}
|
|
|
|
ByValue => {
|
|
|
|
// Actually, this case cannot happen right now,
|
|
|
|
// because structs are never immediate. But in
|
|
|
|
// principle, newtype'd immediate values should be
|
|
|
|
// immediate, and in that case the * would be a no-op
|
|
|
|
// except for changing the type, so I am putting this
|
|
|
|
// code in place here to do the right thing if this
|
|
|
|
// change ever goes through.
|
|
|
|
assert ty::type_is_immediate(ty);
|
2013-02-22 00:41:37 -06:00
|
|
|
(Some(Datum {ty: ty, ..*self}), bcx)
|
2012-10-30 20:31:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => { // not derefable.
|
2013-01-11 23:01:42 -06:00
|
|
|
return (None, bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deref_ptr(bcx: block, lv: &Datum, ty: ty::t) -> Datum {
|
|
|
|
Datum {
|
|
|
|
val: lv.to_value_llval(bcx),
|
|
|
|
ty: ty,
|
|
|
|
mode: ByRef,
|
2013-01-10 12:59:58 -06:00
|
|
|
source: ZeroMem // *p is an lvalue
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn deref(&self, bcx: block,
|
2012-08-28 17:54:45 -05:00
|
|
|
expr: @ast::expr, // the expression whose value is being deref'd
|
2013-01-11 23:01:42 -06:00
|
|
|
derefs: uint)
|
|
|
|
-> DatumBlock {
|
2012-08-28 17:54:45 -05:00
|
|
|
match self.try_deref(bcx, expr.id, derefs, false) {
|
2013-01-11 23:01:42 -06:00
|
|
|
(Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres },
|
|
|
|
(None, _) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
bcx.ccx().sess.span_bug(
|
|
|
|
expr.span, ~"Cannot deref this expression");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn autoderef(&self, bcx: block,
|
2012-08-28 17:54:45 -05:00
|
|
|
expr_id: ast::node_id,
|
2013-01-11 23:01:42 -06:00
|
|
|
max: uint)
|
|
|
|
-> DatumBlock {
|
2012-08-28 17:54:45 -05:00
|
|
|
let _icx = bcx.insn_ctxt("autoderef");
|
|
|
|
|
|
|
|
debug!("autoderef(expr_id=%d, max=%?, self=%?)",
|
|
|
|
expr_id, max, self.to_str(bcx.ccx()));
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
let mut datum = *self;
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut derefs = 0u;
|
2013-01-11 23:01:42 -06:00
|
|
|
let mut bcx = bcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
while derefs < max {
|
|
|
|
derefs += 1u;
|
|
|
|
match datum.try_deref(bcx, expr_id, derefs, true) {
|
2013-01-11 23:01:42 -06:00
|
|
|
(None, new_bcx) => { bcx = new_bcx; break }
|
|
|
|
(Some(datum_deref), new_bcx) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
datum = datum_deref;
|
2013-01-11 23:01:42 -06:00
|
|
|
bcx = new_bcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// either we were asked to deref a specific number of times,
|
|
|
|
// in which case we should have, or we asked to deref as many
|
|
|
|
// times as we can
|
|
|
|
assert derefs == max || max == uint::max_value;
|
2013-01-11 23:01:42 -06:00
|
|
|
DatumBlock { bcx: bcx, datum: datum }
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn get_base_and_len(&self, bcx: block) -> (ValueRef, ValueRef) {
|
2012-08-28 17:54:45 -05:00
|
|
|
tvec::get_base_and_len(bcx, self.to_appropriate_llval(bcx), self.ty)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_result(&self, bcx: block) -> common::Result {
|
2012-08-28 17:54:45 -05:00
|
|
|
rslt(bcx, self.to_appropriate_llval(bcx))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub impl DatumBlock {
|
2013-03-05 19:36:39 -06:00
|
|
|
fn unpack(&self, +bcx: &mut block) -> Datum {
|
2012-08-28 17:54:45 -05:00
|
|
|
*bcx = self.bcx;
|
|
|
|
return self.datum;
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn assert_by_ref(&self) -> DatumBlock {
|
2012-08-28 17:54:45 -05:00
|
|
|
assert self.datum.mode.is_by_ref();
|
2013-02-22 00:41:37 -06:00
|
|
|
*self
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn drop_val(&self) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.datum.drop_val(self.bcx)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn store_to(&self, id: ast::node_id, action: CopyAction,
|
2013-01-10 12:59:58 -06:00
|
|
|
dst: ValueRef) -> block {
|
|
|
|
self.datum.store_to(self.bcx, id, action, dst)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.datum.copy_to(self.bcx, action, dst)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn move_to(&self, action: CopyAction, dst: ValueRef) -> block {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.datum.move_to(self.bcx, action, dst)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_value_llval(&self) -> ValueRef {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.datum.to_value_llval(self.bcx)
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn to_result(&self) -> common::Result {
|
2012-08-28 17:54:45 -05:00
|
|
|
rslt(self.bcx, self.datum.to_appropriate_llval(self.bcx))
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn ccx(&self) -> @CrateContext {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.bcx.ccx()
|
|
|
|
}
|
|
|
|
|
2013-02-22 00:41:37 -06:00
|
|
|
fn tcx(&self) -> ty::ctxt {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.bcx.tcx()
|
|
|
|
}
|
|
|
|
|
2013-02-03 22:47:26 -06:00
|
|
|
fn to_str(&self) -> ~str {
|
2012-08-28 17:54:45 -05:00
|
|
|
self.datum.to_str(self.ccx())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|