Update trans to use type to decide when to move, not the moves table (simpler
for cases where it's hard to decide what id to use for the lookup); modify irrefutable bindings code to move or copy depending on the type, rather than threading through a flag. Also updates how local variables and arguments are registered. These changes were hard to isolate.
This commit is contained in:
parent
41efcdf299
commit
2d3262ca7b
@ -53,7 +53,6 @@ pub struct Maps {
|
||||
method_map: middle::typeck::method_map,
|
||||
vtable_map: middle::typeck::vtable_map,
|
||||
write_guard_map: middle::borrowck::write_guard_map,
|
||||
moves_map: middle::moves::MovesMap,
|
||||
capture_map: middle::moves::CaptureMap,
|
||||
}
|
||||
|
||||
@ -952,12 +951,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
}
|
||||
}
|
||||
|
||||
if maps.moves_map.contains(&id) {
|
||||
do ebml_w.tag(c::tag_table_moves_map) |ebml_w| {
|
||||
ebml_w.id(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let r = maps.capture_map.find(&id);
|
||||
for r.iter().advance |&cap_vars| {
|
||||
@ -1121,9 +1114,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
|
||||
xcx.dcx.tcx.sess.bug(
|
||||
fmt!("unknown tag found in side tables: %x", tag));
|
||||
}
|
||||
Some(value) => if value == c::tag_table_moves_map {
|
||||
dcx.maps.moves_map.insert(id);
|
||||
} else {
|
||||
Some(value) => {
|
||||
let val_doc = entry_doc.get(c::tag_table_val as uint);
|
||||
let mut val_dsr = reader::Decoder(val_doc);
|
||||
let val_dsr = &mut val_dsr;
|
||||
|
@ -187,7 +187,6 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
|
||||
method_map: @mut HashMap::new(),
|
||||
vtable_map: @mut HashMap::new(),
|
||||
write_guard_map: @mut HashSet::new(),
|
||||
moves_map: @mut HashSet::new(),
|
||||
capture_map: @mut HashMap::new()
|
||||
};
|
||||
match csearch::maybe_get_item_ast(tcx, def_id,
|
||||
|
@ -316,7 +316,7 @@ pub fn variant_opt(bcx: block, pat_id: ast::node_id)
|
||||
}
|
||||
|
||||
pub enum TransBindingMode {
|
||||
TrByValue(/*ismove:*/ bool, /*llbinding:*/ ValueRef),
|
||||
TrByValue(/*llbinding:*/ ValueRef),
|
||||
TrByRef,
|
||||
}
|
||||
|
||||
@ -1138,18 +1138,11 @@ fn store_non_ref_bindings(bcx: block,
|
||||
let mut bcx = bcx;
|
||||
for bindings_map.each_value |&binding_info| {
|
||||
match binding_info.trmode {
|
||||
TrByValue(is_move, lldest) => {
|
||||
TrByValue(lldest) => {
|
||||
let llval = Load(bcx, binding_info.llmatch); // get a T*
|
||||
let datum = Datum {val: llval, ty: binding_info.ty,
|
||||
mode: ByRef(ZeroMem)};
|
||||
bcx = {
|
||||
if is_move {
|
||||
datum.move_to(bcx, INIT, lldest)
|
||||
} else {
|
||||
datum.copy_to(bcx, INIT, lldest)
|
||||
}
|
||||
};
|
||||
|
||||
bcx = datum.store_to(bcx, INIT, lldest);
|
||||
do opt_temp_cleanups.mutate |temp_cleanups| {
|
||||
add_clean_temp_mem(bcx, lldest, binding_info.ty);
|
||||
temp_cleanups.push(lldest);
|
||||
@ -1181,7 +1174,7 @@ fn insert_lllocals(bcx: block,
|
||||
let llval = match binding_info.trmode {
|
||||
// By value bindings: use the stack slot that we
|
||||
// copied/moved the value into
|
||||
TrByValue(_, lldest) => {
|
||||
TrByValue(lldest) => {
|
||||
if add_cleans {
|
||||
add_clean(bcx, lldest, binding_info.ty);
|
||||
}
|
||||
@ -1245,7 +1238,7 @@ pub fn compile_guard(bcx: block,
|
||||
let mut bcx = bcx;
|
||||
for data.bindings_map.each_value |&binding_info| {
|
||||
match binding_info.trmode {
|
||||
TrByValue(_, llval) => {
|
||||
TrByValue(llval) => {
|
||||
bcx = glue::drop_ty(bcx, llval, binding_info.ty);
|
||||
}
|
||||
TrByRef => {}
|
||||
@ -1737,53 +1730,204 @@ pub enum IrrefutablePatternBindingMode {
|
||||
BindArgument
|
||||
}
|
||||
|
||||
// Not match-related, but similar to the pattern-munging code above
|
||||
pub fn bind_irrefutable_pat(bcx: block,
|
||||
pat: @ast::pat,
|
||||
val: ValueRef,
|
||||
make_copy: bool,
|
||||
binding_mode: IrrefutablePatternBindingMode)
|
||||
-> block {
|
||||
let _icx = push_ctxt("match::bind_irrefutable_pat");
|
||||
let ccx = bcx.fcx.ccx;
|
||||
pub fn store_local(bcx: block,
|
||||
pat: @ast::pat,
|
||||
opt_init_expr: Option<@ast::expr>)
|
||||
-> block {
|
||||
/*!
|
||||
* Generates code for a local variable declaration like
|
||||
* `let <pat>;` or `let <pat> = <opt_init_expr>`.
|
||||
*/
|
||||
let mut bcx = bcx;
|
||||
|
||||
// Necessary since bind_irrefutable_pat is called outside trans_match
|
||||
match pat.node {
|
||||
ast::pat_ident(_, _, ref inner) => {
|
||||
if pat_is_variant_or_struct(bcx.tcx().def_map, pat) {
|
||||
return bcx;
|
||||
return match opt_init_expr {
|
||||
Some(init_expr) => {
|
||||
// Optimize the "let x = expr" case. This just writes
|
||||
// the result of evaluating `expr` directly into the alloca
|
||||
// for `x`. Often the general path results in similar or the
|
||||
// same code post-optimization, but not always. In particular,
|
||||
// in unsafe code, you can have expressions like
|
||||
//
|
||||
// let x = intrinsics::uninit();
|
||||
//
|
||||
// In such cases, the more general path is unsafe, because
|
||||
// it assumes it is matching against a valid value.
|
||||
match simple_identifier(pat) {
|
||||
Some(path) => {
|
||||
return mk_binding_alloca(
|
||||
bcx, pat.id, path, BindLocal,
|
||||
|bcx, _, llval| expr::trans_into(bcx, init_expr,
|
||||
expr::SaveIn(llval)));
|
||||
}
|
||||
|
||||
None => {}
|
||||
}
|
||||
|
||||
if make_copy {
|
||||
let binding_ty = node_id_type(bcx, pat.id);
|
||||
let datum = Datum {val: val, ty: binding_ty,
|
||||
mode: ByRef(RevokeClean)};
|
||||
let scratch = scratch_datum(bcx, binding_ty, false);
|
||||
datum.copy_to_datum(bcx, INIT, scratch);
|
||||
match binding_mode {
|
||||
BindLocal => {
|
||||
bcx.fcx.lllocals.insert(pat.id, scratch.val);
|
||||
}
|
||||
BindArgument => {
|
||||
bcx.fcx.llargs.insert(pat.id, scratch.val);
|
||||
}
|
||||
}
|
||||
add_clean(bcx, scratch.val, binding_ty);
|
||||
// General path.
|
||||
let init_datum =
|
||||
unpack_datum!(
|
||||
bcx,
|
||||
expr::trans_to_datum(bcx, init_expr));
|
||||
if ty::type_is_bot(expr_ty(bcx, init_expr)) {
|
||||
create_dummy_locals(bcx, pat)
|
||||
} else {
|
||||
match binding_mode {
|
||||
BindLocal => {
|
||||
bcx.fcx.lllocals.insert(pat.id, val);
|
||||
}
|
||||
BindArgument => {
|
||||
bcx.fcx.llargs.insert(pat.id, val);
|
||||
}
|
||||
if bcx.sess().asm_comments() {
|
||||
add_comment(bcx, "creating zeroable ref llval");
|
||||
}
|
||||
let llptr = init_datum.to_zeroable_ref_llval(bcx);
|
||||
return bind_irrefutable_pat(bcx, pat, llptr, BindLocal);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
create_dummy_locals(bcx, pat)
|
||||
}
|
||||
};
|
||||
|
||||
fn create_dummy_locals(mut bcx: block, pat: @ast::pat) -> block {
|
||||
// create dummy memory for the variables if we have no
|
||||
// value to store into them immediately
|
||||
let tcx = bcx.tcx();
|
||||
do pat_bindings(tcx.def_map, pat) |_, p_id, _, path| {
|
||||
bcx = mk_binding_alloca(
|
||||
bcx, p_id, path, BindLocal,
|
||||
|bcx, var_ty, llval| { zero_mem(bcx, llval, var_ty); bcx });
|
||||
}
|
||||
bcx
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_arg(mut bcx: block,
|
||||
pat: @ast::pat,
|
||||
llval: ValueRef)
|
||||
-> block {
|
||||
/*!
|
||||
* Generates code for argument patterns like `fn foo(<pat>: T)`.
|
||||
* Creates entries in the `llargs` map for each of the bindings
|
||||
* in `pat`.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* - `pat` is the argument pattern
|
||||
* - `llval` is a pointer to the argument value (in other words,
|
||||
* if the argument type is `T`, then `llval` is a `T*`). In some
|
||||
* cases, this code may zero out the memory `llval` points at.
|
||||
*/
|
||||
|
||||
// We always need to cleanup the argument as we exit the fn scope.
|
||||
// Note that we cannot do it before for fear of a fn like
|
||||
// fn getaddr(~ref x: ~uint) -> *uint {....}
|
||||
// (From test `run-pass/func-arg-ref-pattern.rs`)
|
||||
let arg_ty = node_id_type(bcx, pat.id);
|
||||
add_clean(bcx, llval, arg_ty);
|
||||
|
||||
match simple_identifier(pat) {
|
||||
Some(_) => {
|
||||
// Optimized path for `x: T` case. This just adopts
|
||||
// `llval` wholesale as the pointer for `x`, avoiding the
|
||||
// general logic which may copy out of `llval`.
|
||||
bcx.fcx.llargs.insert(pat.id, llval);
|
||||
}
|
||||
|
||||
None => {
|
||||
// General path. Copy out the values that are used in the
|
||||
// pattern.
|
||||
bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument);
|
||||
}
|
||||
}
|
||||
|
||||
return bcx;
|
||||
}
|
||||
|
||||
fn mk_binding_alloca(mut bcx: block,
|
||||
p_id: ast::node_id,
|
||||
path: @ast::Path,
|
||||
binding_mode: IrrefutablePatternBindingMode,
|
||||
populate: &fn(block, ty::t, ValueRef) -> block) -> block {
|
||||
let var_ty = node_id_type(bcx, p_id);
|
||||
let ident = ast_util::path_to_ident(path);
|
||||
let llval = alloc_ty(bcx, var_ty, bcx.ident(ident));
|
||||
bcx = populate(bcx, var_ty, llval);
|
||||
let llmap = match binding_mode {
|
||||
BindLocal => bcx.fcx.lllocals,
|
||||
BindArgument => bcx.fcx.llargs
|
||||
};
|
||||
llmap.insert(p_id, llval);
|
||||
add_clean(bcx, llval, var_ty);
|
||||
return bcx;
|
||||
}
|
||||
|
||||
fn bind_irrefutable_pat(bcx: block,
|
||||
pat: @ast::pat,
|
||||
val: ValueRef,
|
||||
binding_mode: IrrefutablePatternBindingMode)
|
||||
-> block {
|
||||
/*!
|
||||
* A simple version of the pattern matching code that only handles
|
||||
* irrefutable patterns. This is used in let/argument patterns,
|
||||
* not in match statements. Unifying this code with the code above
|
||||
* sounds nice, but in practice it produces very inefficient code,
|
||||
* since the match code is so much more general. In most cases,
|
||||
* LLVM is able to optimize the code, but it causes longer compile
|
||||
* times and makes the generated code nigh impossible to read.
|
||||
*
|
||||
* # Arguments
|
||||
* - bcx: starting basic block context
|
||||
* - pat: the irrefutable pattern being matched.
|
||||
* - val: a pointer to the value being matched. If pat matches a value
|
||||
* of type T, then this is a T*. If the value is moved from `pat`,
|
||||
* then `*pat` will be zeroed; otherwise, it's existing cleanup
|
||||
* applies.
|
||||
* - binding_mode: is this for an argument or a local variable?
|
||||
*/
|
||||
|
||||
debug!("bind_irrefutable_pat(bcx=%s, pat=%s, val=%s, binding_mode=%?)",
|
||||
bcx.to_str(),
|
||||
pat_to_str(pat, bcx.sess().intr()),
|
||||
val_str(bcx.ccx().tn, val),
|
||||
binding_mode);
|
||||
|
||||
if bcx.sess().asm_comments() {
|
||||
add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)",
|
||||
pat_to_str(pat, bcx.sess().intr())));
|
||||
}
|
||||
|
||||
let _indenter = indenter();
|
||||
|
||||
let _icx = bcx.insn_ctxt("alt::bind_irrefutable_pat");
|
||||
let mut bcx = bcx;
|
||||
let tcx = bcx.tcx();
|
||||
let ccx = bcx.ccx();
|
||||
match pat.node {
|
||||
ast::pat_ident(pat_binding_mode, path, inner) => {
|
||||
if pat_is_binding(tcx.def_map, pat) {
|
||||
// Allocate the stack slot where the value of this
|
||||
// binding will live and place it into the appropriate
|
||||
// map.
|
||||
bcx = mk_binding_alloca(
|
||||
bcx, pat.id, path, binding_mode,
|
||||
|bcx, variable_ty, llvariable_val| {
|
||||
match pat_binding_mode {
|
||||
ast::bind_infer => {
|
||||
// By value binding: move the value that `val`
|
||||
// points at into the binding's stack slot.
|
||||
let datum = Datum {val: val,
|
||||
ty: variable_ty,
|
||||
mode: ByRef(ZeroMem)};
|
||||
datum.store_to(bcx, INIT, llvariable_val)
|
||||
}
|
||||
|
||||
ast::bind_by_ref(_) => {
|
||||
// By ref binding: the value of the variable
|
||||
// is the pointer `val` itself.
|
||||
Store(bcx, val, llvariable_val);
|
||||
bcx
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for inner.iter().advance |inner_pat| {
|
||||
bcx = bind_irrefutable_pat(
|
||||
bcx, *inner_pat, val, true, binding_mode);
|
||||
for inner.iter().advance |&inner_pat| {
|
||||
bcx = bind_irrefutable_pat(bcx, inner_pat, val, binding_mode);
|
||||
}
|
||||
}
|
||||
ast::pat_enum(_, ref sub_pats) => {
|
||||
@ -1799,11 +1943,8 @@ pub fn bind_irrefutable_pat(bcx: block,
|
||||
val);
|
||||
for sub_pats.iter().advance |sub_pat| {
|
||||
for args.vals.iter().enumerate().advance |(i, argval)| {
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
sub_pat[i],
|
||||
*argval,
|
||||
make_copy,
|
||||
binding_mode);
|
||||
bcx = bind_irrefutable_pat(bcx, sub_pat[i],
|
||||
*argval, binding_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1818,19 +1959,14 @@ pub fn bind_irrefutable_pat(bcx: block,
|
||||
let repr = adt::represent_node(bcx, pat.id);
|
||||
for elems.iter().enumerate().advance |(i, elem)| {
|
||||
let fldptr = adt::trans_field_ptr(bcx, repr,
|
||||
val, 0, i);
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
*elem,
|
||||
fldptr,
|
||||
make_copy,
|
||||
binding_mode);
|
||||
val, 0, i);
|
||||
bcx = bind_irrefutable_pat(bcx, *elem,
|
||||
fldptr, binding_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(&ast::def_static(_, false)) => {
|
||||
bcx = bind_irrefutable_pat(bcx, pat, val, make_copy,
|
||||
binding_mode);
|
||||
}
|
||||
_ => {
|
||||
// Nothing to do here.
|
||||
@ -1845,12 +1981,8 @@ pub fn bind_irrefutable_pat(bcx: block,
|
||||
for fields.iter().advance |f| {
|
||||
let ix = ty::field_idx_strict(tcx, f.ident, field_tys);
|
||||
let fldptr = adt::trans_field_ptr(bcx, pat_repr, val,
|
||||
discr, ix);
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
f.pat,
|
||||
fldptr,
|
||||
make_copy,
|
||||
binding_mode);
|
||||
discr, ix);
|
||||
bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, binding_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1858,11 +1990,7 @@ pub fn bind_irrefutable_pat(bcx: block,
|
||||
let repr = adt::represent_node(bcx, pat.id);
|
||||
for elems.iter().enumerate().advance |(i, elem)| {
|
||||
let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i);
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
*elem,
|
||||
fldptr,
|
||||
make_copy,
|
||||
binding_mode);
|
||||
bcx = bind_irrefutable_pat(bcx, *elem, fldptr, binding_mode);
|
||||
}
|
||||
}
|
||||
ast::pat_box(inner) | ast::pat_uniq(inner) => {
|
||||
@ -1872,22 +2000,30 @@ pub fn bind_irrefutable_pat(bcx: block,
|
||||
ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox,
|
||||
_ => GEPi(bcx, llbox, [0u, abi::box_field_body])
|
||||
};
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
inner,
|
||||
unboxed,
|
||||
true,
|
||||
binding_mode);
|
||||
bcx = bind_irrefutable_pat(bcx, inner, unboxed, binding_mode);
|
||||
}
|
||||
ast::pat_region(inner) => {
|
||||
let loaded_val = Load(bcx, val);
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
inner,
|
||||
loaded_val,
|
||||
true,
|
||||
binding_mode);
|
||||
bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode);
|
||||
}
|
||||
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
|
||||
ast::pat_vec(*) => ()
|
||||
ast::pat_vec(*) => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
pat.span,
|
||||
fmt!("vector patterns are never irrefutable!"));
|
||||
}
|
||||
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => ()
|
||||
}
|
||||
return bcx;
|
||||
}
|
||||
|
||||
fn simple_identifier(pat: @ast::pat) -> Option<@ast::Path> {
|
||||
match pat.node {
|
||||
ast::pat_ident(ast::bind_infer, path, None) => {
|
||||
Some(path)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ use middle::trans::type_of::*;
|
||||
use middle::ty;
|
||||
use util::common::indenter;
|
||||
use util::ppaux::{Repr, ty_to_str};
|
||||
use middle::pat_util;
|
||||
|
||||
use middle::trans::type_::Type;
|
||||
|
||||
@ -75,7 +76,7 @@ use extra::time;
|
||||
use extra::sort;
|
||||
use syntax::ast::ident;
|
||||
use syntax::ast_map::{path, path_elt_to_str, path_name};
|
||||
use syntax::ast_util::{local_def, path_to_ident};
|
||||
use syntax::ast_util::{local_def};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::span;
|
||||
use syntax::parse::token;
|
||||
@ -1121,9 +1122,6 @@ pub fn init_local(bcx: block, local: &ast::local) -> block {
|
||||
let _indenter = indenter();
|
||||
|
||||
let _icx = push_ctxt("init_local");
|
||||
let ty = node_id_type(bcx, local.node.id);
|
||||
|
||||
debug!("ty=%s", bcx.ty_to_str(ty));
|
||||
|
||||
if ignore_lhs(bcx, local) {
|
||||
// Handle let _ = e; just like e;
|
||||
@ -1135,36 +1133,7 @@ pub fn init_local(bcx: block, local: &ast::local) -> block {
|
||||
}
|
||||
}
|
||||
|
||||
let llptr = match bcx.fcx.lllocals.find_copy(&local.node.id) {
|
||||
Some(v) => v,
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(local.span,
|
||||
"init_local: Someone forgot to document why it's\
|
||||
safe to assume local.node.init must be local_mem!");
|
||||
}
|
||||
};
|
||||
|
||||
let mut bcx = bcx;
|
||||
match local.node.init {
|
||||
Some(init) => {
|
||||
bcx = expr::trans_into(bcx, init, expr::SaveIn(llptr));
|
||||
}
|
||||
_ => {
|
||||
zero_mem(bcx, llptr, ty);
|
||||
}
|
||||
}
|
||||
|
||||
// Make a note to drop this slot on the way out.
|
||||
debug!("adding clean for %?/%s to bcx=%s",
|
||||
local.node.id, bcx.ty_to_str(ty),
|
||||
bcx.to_str());
|
||||
add_clean(bcx, llptr, ty);
|
||||
|
||||
return _match::bind_irrefutable_pat(bcx,
|
||||
local.node.pat,
|
||||
llptr,
|
||||
false,
|
||||
_match::BindLocal);
|
||||
_match::store_local(bcx, local.node.pat, local.node.init)
|
||||
}
|
||||
|
||||
pub fn trans_stmt(cx: block, s: &ast::stmt) -> block {
|
||||
@ -1469,6 +1438,7 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) {
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< variant A
|
||||
pub fn alloc_local(cx: block, local: &ast::local) -> block {
|
||||
let _icx = push_ctxt("alloc_local");
|
||||
let t = node_id_type(cx, local.node.id);
|
||||
@ -1491,6 +1461,31 @@ pub fn alloc_local(cx: block, local: &ast::local) -> block {
|
||||
}
|
||||
|
||||
|
||||
>>>>>>> variant B
|
||||
####### Ancestor
|
||||
pub fn alloc_local(cx: block, local: @ast::local) -> block {
|
||||
let _icx = push_ctxt("alloc_local");
|
||||
let t = node_id_type(cx, local.node.id);
|
||||
let simple_name = match local.node.pat.node {
|
||||
ast::pat_ident(_, pth, None) => Some(path_to_ident(pth)),
|
||||
_ => None
|
||||
};
|
||||
let val = alloc_ty(cx, t);
|
||||
if cx.sess().opts.debuginfo {
|
||||
for simple_name.iter().advance |name| {
|
||||
str::as_c_str(cx.ccx().sess.str_of(*name), |buf| {
|
||||
unsafe {
|
||||
llvm::LLVMSetValueName(val, buf)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
cx.fcx.lllocals.insert(local.node.id, val);
|
||||
cx
|
||||
}
|
||||
|
||||
|
||||
======= end
|
||||
pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block {
|
||||
let _icx = push_ctxt("with_cond");
|
||||
let next_cx = base::sub_block(bcx, "next");
|
||||
@ -1739,6 +1734,7 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt,
|
||||
let arg = &args[i];
|
||||
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
|
||||
|
||||
// FIXME #7260: aliasing should be determined by monomorphized ty::t
|
||||
match arg.ty.node {
|
||||
// `~` pointers never alias other parameters, because ownership was transferred
|
||||
ast::ty_uniq(_) => {
|
||||
@ -1783,7 +1779,6 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
|
||||
for uint::range(0, arg_tys.len()) |arg_n| {
|
||||
let arg_ty = arg_tys[arg_n];
|
||||
let raw_llarg = raw_llargs[arg_n];
|
||||
let arg_id = args[arg_n].id;
|
||||
|
||||
// For certain mode/type combinations, the raw llarg values are passed
|
||||
// by value. However, within the fn body itself, we want to always
|
||||
@ -1794,22 +1789,13 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
|
||||
// the event it's not truly needed.
|
||||
// only by value if immediate:
|
||||
let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() {
|
||||
let alloc = alloc_ty(bcx, arg_ty);
|
||||
let alloc = alloc_ty(bcx, arg_ty, "__arg");
|
||||
Store(bcx, raw_llarg, alloc);
|
||||
alloc
|
||||
} else {
|
||||
raw_llarg
|
||||
};
|
||||
|
||||
add_clean(bcx, llarg, arg_ty);
|
||||
|
||||
bcx = _match::bind_irrefutable_pat(bcx,
|
||||
args[arg_n].pat,
|
||||
llarg,
|
||||
false,
|
||||
_match::BindArgument);
|
||||
|
||||
fcx.llargs.insert(arg_id, llarg);
|
||||
bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
|
||||
|
||||
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
|
||||
debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span);
|
||||
@ -1968,81 +1954,51 @@ pub fn trans_fn(ccx: @mut CrateContext,
|
||||
|_bcx| { });
|
||||
}
|
||||
|
||||
fn insert_synthetic_type_entries(bcx: block,
|
||||
fn_args: &[ast::arg],
|
||||
arg_tys: &[ty::t])
|
||||
{
|
||||
/*!
|
||||
* For tuple-like structs and enum-variants, we generate
|
||||
* synthetic AST nodes for the arguments. These have no types
|
||||
* in the type table and no entries in the moves table,
|
||||
* so the code in `copy_args_to_allocas` and `bind_irrefutable_pat`
|
||||
* gets upset. This hack of a function bridges the gap by inserting types.
|
||||
*
|
||||
* This feels horrible. I think we should just have a special path
|
||||
* for these functions and not try to use the generic code, but
|
||||
* that's not the problem I'm trying to solve right now. - nmatsakis
|
||||
*/
|
||||
|
||||
let tcx = bcx.tcx();
|
||||
for uint::range(0, fn_args.len()) |i| {
|
||||
debug!("setting type of argument %u (pat node %d) to %s",
|
||||
i, fn_args[i].pat.id, bcx.ty_to_str(arg_tys[i]));
|
||||
|
||||
let pat_id = fn_args[i].pat.id;
|
||||
let arg_ty = arg_tys[i];
|
||||
tcx.node_types.insert(pat_id as uint, arg_ty);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_enum_variant(ccx: @mut CrateContext,
|
||||
enum_id: ast::node_id,
|
||||
_enum_id: ast::node_id,
|
||||
variant: &ast::variant,
|
||||
args: &[ast::variant_arg],
|
||||
disr: int,
|
||||
param_substs: Option<@param_substs>,
|
||||
llfndecl: ValueRef) {
|
||||
let _icx = push_ctxt("trans_enum_variant");
|
||||
// Translate variant arguments to function arguments.
|
||||
let fn_args = do args.map |varg| {
|
||||
ast::arg {
|
||||
is_mutbl: false,
|
||||
ty: copy varg.ty,
|
||||
pat: ast_util::ident_to_pat(
|
||||
ccx.tcx.sess.next_node_id(),
|
||||
codemap::dummy_sp(),
|
||||
special_idents::arg),
|
||||
id: varg.id,
|
||||
}
|
||||
};
|
||||
|
||||
let ty_param_substs = match param_substs {
|
||||
Some(ref substs) => { copy substs.tys }
|
||||
None => ~[]
|
||||
};
|
||||
let enum_ty = ty::subst_tps(ccx.tcx,
|
||||
ty_param_substs,
|
||||
None,
|
||||
ty::node_id_to_type(ccx.tcx, enum_id));
|
||||
let fcx = new_fn_ctxt_w_id(ccx,
|
||||
~[],
|
||||
llfndecl,
|
||||
variant.node.id,
|
||||
enum_ty,
|
||||
param_substs,
|
||||
None);
|
||||
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
let lltop = bcx.llbb;
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
|
||||
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
|
||||
|
||||
// XXX is there a better way to reconstruct the ty::t?
|
||||
let repr = adt::represent_type(ccx, enum_ty);
|
||||
|
||||
debug!("trans_enum_variant: name=%s tps=%s repr=%? enum_ty=%s",
|
||||
unsafe { str::raw::from_c_str(llvm::LLVMGetValueName(llfndecl)) },
|
||||
~"[" + ty_param_substs.map(|&t| ty_to_str(ccx.tcx, t)).connect(", ") + "]",
|
||||
repr, ty_to_str(ccx.tcx, enum_ty));
|
||||
|
||||
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
|
||||
for args.iter().enumerate().advance |(i, va)| {
|
||||
let lldestptr = adt::trans_field_ptr(bcx,
|
||||
repr,
|
||||
fcx.llretptr.get(),
|
||||
disr,
|
||||
i);
|
||||
|
||||
// If this argument to this function is a enum, it'll have come in to
|
||||
// this function as an opaque blob due to the way that type_of()
|
||||
// works. So we have to cast to the destination's view of the type.
|
||||
let llarg = match fcx.llargs.find(&va.id) {
|
||||
Some(&x) => x,
|
||||
_ => fail!("trans_enum_variant: how do we know this works?"),
|
||||
};
|
||||
let arg_ty = arg_tys[i];
|
||||
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
|
||||
}
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
trans_enum_variant_or_tuple_like_struct(
|
||||
ccx,
|
||||
variant.node.id,
|
||||
args,
|
||||
disr,
|
||||
param_substs,
|
||||
llfndecl);
|
||||
}
|
||||
|
||||
// NB: In theory this should be merged with the function above. But the AST
|
||||
// structures are completely different, so very little code would be shared.
|
||||
pub fn trans_tuple_struct(ccx: @mut CrateContext,
|
||||
fields: &[@ast::struct_field],
|
||||
ctor_id: ast::node_id,
|
||||
@ -2050,37 +2006,72 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
|
||||
llfndecl: ValueRef) {
|
||||
let _icx = push_ctxt("trans_tuple_struct");
|
||||
|
||||
// Translate struct fields to function arguments.
|
||||
let fn_args = do fields.map |field| {
|
||||
trans_enum_variant_or_tuple_like_struct(
|
||||
ccx,
|
||||
ctor_id,
|
||||
fields,
|
||||
0,
|
||||
param_substs,
|
||||
llfndecl);
|
||||
}
|
||||
|
||||
trait IdAndTy {
|
||||
fn id(&self) -> ast::node_id;
|
||||
fn ty(&self) -> @ast::Ty;
|
||||
}
|
||||
|
||||
impl IdAndTy for ast::variant_arg {
|
||||
fn id(&self) -> ast::node_id { self.id }
|
||||
fn ty(&self) -> @ast::Ty { self.ty }
|
||||
}
|
||||
|
||||
impl IdAndTy for @ast::struct_field {
|
||||
fn id(&self) -> ast::node_id { self.node.id }
|
||||
fn ty(&self) -> @ast::Ty { self.node.ty }
|
||||
}
|
||||
|
||||
pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
|
||||
ccx: @mut CrateContext,
|
||||
ctor_id: ast::node_id,
|
||||
args: &[A],
|
||||
disr: int,
|
||||
param_substs: Option<@param_substs>,
|
||||
llfndecl: ValueRef)
|
||||
{
|
||||
// Translate variant arguments to function arguments.
|
||||
let fn_args = do args.map |varg| {
|
||||
ast::arg {
|
||||
is_mutbl: false,
|
||||
ty: copy field.node.ty,
|
||||
pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(),
|
||||
codemap::dummy_sp(),
|
||||
special_idents::arg),
|
||||
id: field.node.id
|
||||
ty: varg.ty(),
|
||||
pat: ast_util::ident_to_pat(
|
||||
ccx.tcx.sess.next_node_id(),
|
||||
codemap::dummy_sp(),
|
||||
special_idents::arg),
|
||||
id: varg.id(),
|
||||
}
|
||||
};
|
||||
|
||||
// XXX is there a better way to reconstruct the ty::t?
|
||||
let ty_param_substs = match param_substs {
|
||||
Some(ref substs) => { copy substs.tys }
|
||||
None => ~[]
|
||||
};
|
||||
|
||||
let ctor_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None,
|
||||
ty::node_id_to_type(ccx.tcx, ctor_id));
|
||||
let tup_ty = match ty::get(ctor_ty).sty {
|
||||
|
||||
let result_ty = match ty::get(ctor_ty).sty {
|
||||
ty::ty_bare_fn(ref bft) => bft.sig.output,
|
||||
_ => ccx.sess.bug(fmt!("trans_tuple_struct: unexpected ctor \
|
||||
return type %s",
|
||||
ty_to_str(ccx.tcx, ctor_ty)))
|
||||
_ => ccx.sess.bug(
|
||||
fmt!("trans_enum_variant_or_tuple_like_struct: \
|
||||
unexpected ctor return type %s",
|
||||
ty_to_str(ccx.tcx, ctor_ty)))
|
||||
};
|
||||
|
||||
let fcx = new_fn_ctxt_w_id(ccx,
|
||||
~[],
|
||||
llfndecl,
|
||||
ctor_id,
|
||||
tup_ty,
|
||||
result_ty,
|
||||
param_substs,
|
||||
None);
|
||||
|
||||
@ -2088,23 +2079,23 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
|
||||
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
let lltop = bcx.llbb;
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
|
||||
let arg_tys = ty::ty_fn_args(ctor_ty);
|
||||
|
||||
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
|
||||
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
|
||||
|
||||
let repr = adt::represent_type(ccx, tup_ty);
|
||||
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0);
|
||||
|
||||
for fields.iter().enumerate().advance |(i, field)| {
|
||||
let repr = adt::represent_type(ccx, result_ty);
|
||||
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
|
||||
for fn_args.iter().enumerate().advance |(i, fn_arg)| {
|
||||
let lldestptr = adt::trans_field_ptr(bcx,
|
||||
repr,
|
||||
fcx.llretptr.get(),
|
||||
0,
|
||||
disr,
|
||||
i);
|
||||
let llarg = fcx.llargs.get_copy(&field.node.id);
|
||||
let llarg = fcx.llargs.get_copy(&fn_arg.pat.id);
|
||||
let arg_ty = arg_tys[i];
|
||||
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
|
||||
}
|
||||
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
}
|
||||
@ -3039,8 +3030,8 @@ pub fn trans_crate(sess: session::Session,
|
||||
}
|
||||
}
|
||||
if ccx.sess.count_llvm_insns() {
|
||||
for ccx.stats.llvm_insns.iter().advance |(&k, &v)| {
|
||||
io::println(fmt!("%-7u %s", v, k));
|
||||
for ccx.stats.llvm_insns.each |k, v| {
|
||||
io::println(fmt!("%-7u %s", *v, *k));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -860,8 +860,6 @@ pub fn trans_arg_expr(bcx: block,
|
||||
// FIXME(#3548) use the adjustments table
|
||||
match autoref_arg {
|
||||
DoAutorefArg => {
|
||||
assert!(!
|
||||
bcx.ccx().maps.moves_map.contains(&arg_expr.id));
|
||||
val = arg_datum.to_ref_llval(bcx);
|
||||
}
|
||||
DontAutorefArg => {
|
||||
|
@ -35,9 +35,6 @@ use syntax::codemap::span;
|
||||
pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block {
|
||||
let _icx = push_ctxt("trans_block");
|
||||
let mut bcx = bcx;
|
||||
do block_locals(b) |local| {
|
||||
bcx = alloc_local(bcx, local);
|
||||
};
|
||||
for b.node.stmts.iter().advance |s| {
|
||||
debuginfo::update_source_pos(bcx, b.span);
|
||||
bcx = trans_stmt(bcx, *s);
|
||||
|
@ -70,8 +70,8 @@
|
||||
* This is a "shallow" clone. After `move_to()`, the current datum
|
||||
* is invalid and should no longer be used.
|
||||
*
|
||||
* - `store_to()` either performs a copy or a move by consulting the
|
||||
* moves_map computed by `middle::moves`.
|
||||
* - `store_to()` either performs a copy or a move depending on the
|
||||
* Rust type of the datum.
|
||||
*
|
||||
* # Scratch datum
|
||||
*
|
||||
@ -208,7 +208,6 @@ pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
|
||||
impl Datum {
|
||||
pub fn store_to(&self,
|
||||
bcx: block,
|
||||
id: ast::node_id,
|
||||
action: CopyAction,
|
||||
dst: ValueRef)
|
||||
-> block {
|
||||
@ -218,7 +217,7 @@ impl Datum {
|
||||
* `id` is located in the move table, but copies otherwise.
|
||||
*/
|
||||
|
||||
if bcx.ccx().maps.moves_map.contains(&id) {
|
||||
if ty::type_moves_by_default(bcx.tcx(), self.ty) {
|
||||
self.move_to(bcx, action, dst)
|
||||
} else {
|
||||
self.copy_to(bcx, action, dst)
|
||||
@ -227,7 +226,6 @@ impl Datum {
|
||||
|
||||
pub fn store_to_dest(&self,
|
||||
bcx: block,
|
||||
id: ast::node_id,
|
||||
dest: expr::Dest)
|
||||
-> block {
|
||||
match dest {
|
||||
@ -235,21 +233,20 @@ impl Datum {
|
||||
return bcx;
|
||||
}
|
||||
expr::SaveIn(addr) => {
|
||||
return self.store_to(bcx, id, INIT, addr);
|
||||
return self.store_to(bcx, INIT, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_to_datum(&self,
|
||||
bcx: block,
|
||||
id: ast::node_id,
|
||||
action: CopyAction,
|
||||
datum: Datum)
|
||||
-> block {
|
||||
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());
|
||||
self.store_to(bcx, id, action, datum.val)
|
||||
self.store_to(bcx, action, datum.val)
|
||||
}
|
||||
|
||||
pub fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
|
||||
@ -828,11 +825,10 @@ impl DatumBlock {
|
||||
}
|
||||
|
||||
pub fn store_to(&self,
|
||||
id: ast::node_id,
|
||||
action: CopyAction,
|
||||
dst: ValueRef)
|
||||
-> block {
|
||||
self.datum.store_to(self.bcx, id, action, dst)
|
||||
self.datum.store_to(self.bcx, action, dst)
|
||||
}
|
||||
|
||||
pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block {
|
||||
|
@ -23,7 +23,8 @@ This will generate code that evaluates `expr`, storing the result into
|
||||
`Dest`, which must either be the special flag ignore (throw the result
|
||||
away) or be a pointer to memory of the same type/size as the
|
||||
expression. It returns the resulting basic block. This form will
|
||||
handle all automatic adjustments and moves for you.
|
||||
handle all automatic adjustments for you. The value will be moved if
|
||||
its type is linear and copied otherwise.
|
||||
|
||||
## Translation to a datum
|
||||
|
||||
@ -42,18 +43,18 @@ This function generates code to evaluate the expression and return a
|
||||
tries to return its result in the most efficient way possible, without
|
||||
introducing extra copies or sacrificing information. Therefore, for
|
||||
lvalue expressions, you always get a by-ref `Datum` in return that
|
||||
points at the memory for this lvalue (almost, see [1]). For rvalue
|
||||
expressions, we will return a by-value `Datum` whenever possible, but
|
||||
it is often necessary to allocate a stack slot, store the result of
|
||||
the rvalue in there, and then return a pointer to the slot (see the
|
||||
discussion later on about the different kinds of rvalues).
|
||||
points at the memory for this lvalue. For rvalue expressions, we will
|
||||
return a by-value `Datum` whenever possible, but it is often necessary
|
||||
to allocate a stack slot, store the result of the rvalue in there, and
|
||||
then return a pointer to the slot (see the discussion later on about
|
||||
the different kinds of rvalues).
|
||||
|
||||
NB: The `trans_to_datum()` function does perform adjustments, but
|
||||
since it returns a pointer to the value "in place" it does not handle
|
||||
any moves that may be relevant. If you are transing an expression
|
||||
whose result should be moved, you should either use the Datum methods
|
||||
`move_to()` (for unconditional moves) or `store_to()` (for moves
|
||||
conditioned on the type of the expression) at some point.
|
||||
moves. If you wish to copy/move the value returned into a new
|
||||
location, you should use the Datum method `store_to()` (move or copy
|
||||
depending on type). You can also use `move_to()` (force move) or
|
||||
`copy_to()` (force copy) for special situations.
|
||||
|
||||
## Translating local variables
|
||||
|
||||
@ -110,13 +111,6 @@ generate phi nodes).
|
||||
Finally, statement rvalues are rvalues that always produce a nil
|
||||
return type, such as `while` loops or assignments (`a = b`).
|
||||
|
||||
## Caveats
|
||||
|
||||
[1] Actually, some lvalues are only stored by value and not by
|
||||
reference. An example (as of this writing) would be immutable
|
||||
arguments or pattern bindings of immediate type. However, mutable
|
||||
lvalues are *never* stored by value.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@ -315,7 +309,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
|
||||
let datumblock = trans_to_datum(bcx, expr);
|
||||
return match dest {
|
||||
Ignore => datumblock.bcx,
|
||||
SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
|
||||
SaveIn(lldest) => datumblock.store_to(INIT, lldest)
|
||||
};
|
||||
}
|
||||
|
||||
@ -343,7 +337,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
|
||||
let datumblock = trans_lvalue_unadjusted(bcx, expr);
|
||||
match dest {
|
||||
Ignore => datumblock.bcx,
|
||||
SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
|
||||
SaveIn(lldest) => datumblock.store_to(INIT, lldest)
|
||||
}
|
||||
}
|
||||
ty::RvalueDatumExpr => {
|
||||
@ -351,8 +345,9 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
|
||||
match dest {
|
||||
Ignore => datumblock.drop_val(),
|
||||
|
||||
// NB: We always do `move_to()` regardless of the
|
||||
// moves_map because we're processing an rvalue
|
||||
// When processing an rvalue, the value will be newly
|
||||
// allocated, so we always `move_to` so as not to
|
||||
// unnecessarily inc ref counts and so forth:
|
||||
SaveIn(lldest) => datumblock.move_to(INIT, lldest)
|
||||
}
|
||||
}
|
||||
@ -386,11 +381,11 @@ fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
|
||||
|
||||
fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
|
||||
/*!
|
||||
*
|
||||
* Translates an expression into a datum. If this expression
|
||||
* is an rvalue, this will result in a temporary value being
|
||||
* created. If you already know where the result should be stored,
|
||||
* you should use `trans_into()` instead. */
|
||||
* created. If you plan to store the value somewhere else,
|
||||
* you should prefer `trans_into()` instead.
|
||||
*/
|
||||
|
||||
let mut bcx = bcx;
|
||||
|
||||
@ -535,7 +530,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
|
||||
let dst_datum = unpack_datum!(
|
||||
bcx, trans_lvalue(bcx, dst));
|
||||
return src_datum.store_to_datum(
|
||||
bcx, src.id, DROP_EXISTING, dst_datum);
|
||||
bcx, DROP_EXISTING, dst_datum);
|
||||
}
|
||||
ast::expr_assign_op(callee_id, op, dst, src) => {
|
||||
return trans_assign_op(bcx, expr, callee_id, op, dst, src);
|
||||
@ -638,7 +633,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
|
||||
return trans_into(bcx, blk, dest);
|
||||
}
|
||||
ast::expr_copy(a) => {
|
||||
return trans_into(bcx, a, dest);
|
||||
// If we just called `trans_into(bcx, a, dest)`, then this
|
||||
// might *move* the value into `dest` if the value is
|
||||
// non-copyable. So first get a datum and then do an
|
||||
// explicit copy.
|
||||
let datumblk = trans_to_datum(bcx, a);
|
||||
return match dest {
|
||||
Ignore => datumblk.bcx,
|
||||
SaveIn(llval) => datumblk.copy_to(INIT, llval)
|
||||
};
|
||||
}
|
||||
ast::expr_call(f, ref args, _) => {
|
||||
return callee::trans_call(
|
||||
@ -1221,6 +1224,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
|
||||
bcx = trans_into(bcx, e, Ignore);
|
||||
}
|
||||
for optbase.iter().advance |sbi| {
|
||||
// FIXME #7261: this moves entire base, not just certain fields
|
||||
bcx = trans_into(bcx, sbi.expr, Ignore);
|
||||
}
|
||||
return bcx;
|
||||
@ -1245,7 +1249,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
|
||||
adt::trans_field_ptr(bcx, repr, srcval, discr, i)
|
||||
};
|
||||
let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
|
||||
bcx = datum.store_to(bcx, base.expr.id, INIT, dest);
|
||||
bcx = datum.store_to(bcx, INIT, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user