diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 72b6f8e1c805..7412eba11563 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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; diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index bf91b6771dcd..af39dea6d79e 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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, diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a58ee2840467..a9a3c9317b44 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -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 ;` or `let = `. + */ 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(: 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 + } + } +} + diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 8da7c1351c7b..75d9f89a8d7d 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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( + 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)); } } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index cf81def3abf7..216338e11178 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -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 => { diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 8ca4253ead8b..904e6e14e28d 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -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); diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index ed0adbcff873..1de619433afb 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -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 { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 2d5ac23b3b38..19a0f7262ff6 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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); } }