diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index a75a46e64c7f..a1981e1d2832 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -148,26 +148,24 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, time(time_passes, "freevar finding", bind freevars::annotate_freevars(sess, def_map, crate)); let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars); - time::<()>(time_passes, "typechecking", - bind typeck::check_crate(ty_cx, crate)); - time::<()>(time_passes, "alt checking", - bind middle::check_alt::check_crate(ty_cx, crate)); + time(time_passes, "typechecking", + bind typeck::check_crate(ty_cx, crate)); + time(time_passes, "alt checking", + bind middle::check_alt::check_crate(ty_cx, crate)); if sess.get_opts().run_typestate { time(time_passes, "typestate checking", bind middle::tstate::ck::check_crate(ty_cx, crate)); } - time(time_passes, "alias checking", - bind middle::alias::check_crate(ty_cx, crate)); - time::<()>(time_passes, "kind checking", - bind kind::check_crate(ty_cx, crate)); + let mut_map = time(time_passes, "alias checking", + bind middle::alias::check_crate(ty_cx, crate)); + time(time_passes, "kind checking", + bind kind::check_crate(ty_cx, crate)); if sess.get_opts().no_trans { ret; } - let llmod = - time::(time_passes, "translation", - bind trans::trans_crate(sess, crate, - ty_cx, output, - ast_map)); - time::<()>(time_passes, "LLVM passes", - bind link::write::run_passes(sess, llmod, output)); + let llmod = time(time_passes, "translation", + bind trans::trans_crate(sess, crate, ty_cx, output, + ast_map, mut_map)); + time(time_passes, "LLVM passes", + bind link::write::run_passes(sess, llmod, output)); } fn pretty_print_input(sess: session::session, cfg: ast::crate_cfg, input: str, diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 738489bb4006..e29c06c92395 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -36,20 +36,25 @@ type scope = @[restrict]; tag local_info { arg(ast::mode); objfield(ast::mutability); } -type ctx = {tcx: ty::ctxt, local_map: std::map::hashmap}; +type mut_map = std::map::hashmap; +type ctx = {tcx: ty::ctxt, + local_map: std::map::hashmap, + mut_map: mut_map}; -fn check_crate(tcx: ty::ctxt, crate: &@ast::crate) { +fn check_crate(tcx: ty::ctxt, crate: &@ast::crate) -> mut_map { // Stores information about object fields and function // arguments that's otherwise not easily available. - let cx = @{tcx: tcx, local_map: std::map::new_int_hash()}; - let v = - @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _), - visit_item: bind visit_item(cx, _, _, _), - visit_expr: bind visit_expr(cx, _, _, _), - visit_decl: bind visit_decl(cx, _, _, _) - with *visit::default_visitor::()}; + let cx = @{tcx: tcx, + local_map: std::map::new_int_hash(), + mut_map: std::map::new_int_hash()}; + let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _), + visit_item: bind visit_item(cx, _, _, _), + visit_expr: bind visit_expr(cx, _, _, _), + visit_decl: bind visit_decl(cx, _, _, _) + with *visit::default_visitor::()}; visit::visit_crate(*crate, @[], visit::mk_vt(v)); tcx.sess.abort_if_errors(); + ret cx.mut_map; } fn visit_fn(cx: &@ctx, f: &ast::_fn, _tp: &[ast::ty_param], _sp: &span, @@ -425,6 +430,7 @@ fn check_lval(cx: &@ctx, dest: &@ast::expr, sc: &scope, v: &vt) { alt dest.node { ast::expr_path(p) { let dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id)).node; + cx.mut_map.insert(dnum, ()); if is_immutable_alias(*cx, sc, dnum) { cx.tcx.sess.span_err(dest.span, "assigning to immutable alias"); } else if is_immutable_objfield(*cx, dnum) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index aecbe6a05f6f..8932300257c8 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3443,7 +3443,7 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], // First, synthesize a tuple type containing the types of all the // bound expressions. - // bindings_ty = ~[bound_ty1, bound_ty2, ...] + // bindings_ty = [bound_ty1, bound_ty2, ...] let bindings_ty: ty::t = ty::mk_tup(bcx_tcx(bcx), bound_tys); // NB: keep this in sync with T_closure_ptr; we're making @@ -4323,16 +4323,8 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t, if is_val { T_ptr(llout_arg_ty) } else { llout_arg_ty }; val = bcx.build.PointerCast(val, ty); } - if is_val { - if type_is_immediate(cx.ccx, e_ty) { - val = bcx.build.Load(val); - bcx = copy_ty(bcx, val, e_ty).bcx; - } else { - bcx = copy_ty(bcx, val, e_ty).bcx; - if !ty::type_is_structural(cx.ccx.tcx, e_ty) { - val = bcx.build.Load(val); - } - } + if is_val && type_is_immediate(cx.ccx, e_ty) { + val = bcx.build.Load(val); } llargs += [val]; b += 1; @@ -4343,15 +4335,7 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t, none. { let arg: ValueRef = llvm::LLVMGetParam(llthunk, a); if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) { - - // If the argument was passed by value and isn't a - // pointer type, we need to spill it to an alloca in - // order to do a pointer cast. Argh. - if is_val && !ty::type_is_boxed(cx.ccx.tcx, out_arg.ty) { - let argp = do_spill(bcx, arg); - argp = bcx.build.PointerCast(argp, T_ptr(llout_arg_ty)); - arg = bcx.build.Load(argp); - } else { arg = bcx.build.PointerCast(arg, llout_arg_ty); } + arg = bcx.build.PointerCast(arg, llout_arg_ty); } llargs += [arg]; a += 1u; @@ -4371,7 +4355,7 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t, type_of_fn_from_ty(bcx_ccx(bcx), sp, outgoing_fty, ty_param_count); lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty))); lltargetfn = bcx.build.Load(lltargetfn); - llvm::LLVMSetTailCall(bcx.build.FastCall(lltargetfn, llargs), 1); + bcx.build.FastCall(lltargetfn, llargs); build_return(bcx); finish_fn(fcx, lltop); ret {val: llthunk, ty: llthunk_ty}; @@ -4468,29 +4452,30 @@ fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef, // to have type lldestty0 (the callee's expected type). val = llvm::LLVMGetUndef(lldestty0); } else if arg.mode == ty::mo_val { - if ty::type_owns_heap_mem(ccx.tcx, e_ty) { + // Eliding take/drop for appending of external vectors currently + // corrupts memory. I can't figure out why, and external vectors + // are on the way out anyway, so this simply turns off the + // optimization for that case. + let is_ext_vec_plus = alt e.node { + ast::expr_binary(_, _, _) { + ty::type_is_sequence(ccx.tcx, e_ty) && + !ty::sequence_is_interior(ccx.tcx, e_ty) + } + _ { false } + }; + if !lv.is_mem && !is_ext_vec_plus { + // Do nothing for temporaries, just give them to callee + } else if ty::type_is_structural(ccx.tcx, e_ty) { let dst = alloc_ty(bcx, e_ty); + bcx = copy_val(dst.bcx, INIT, dst.val, val, e_ty).bcx; val = dst.val; - bcx = move_val_if_temp(dst.bcx, INIT, val, lv, e_ty).bcx; - } else if lv.is_mem { - val = load_if_immediate(bcx, val, e_ty); - bcx = copy_ty(bcx, val, e_ty).bcx; + add_clean_temp(bcx, val, e_ty); } else { - // Eliding take/drop for appending of external vectors currently - // corrupts memory. I can't figure out why, and external vectors - // are on the way out anyway, so this simply turns off the - // optimization for that case. - let is_ext_vec_plus = - alt e.node { - ast::expr_binary(_, _, _) { - ty::type_is_sequence(ccx.tcx, e_ty) && - !ty::sequence_is_interior(ccx.tcx, e_ty) - } - _ { false } - }; - if is_ext_vec_plus { - bcx = copy_ty(bcx, val, e_ty).bcx; - } else { revoke_clean(bcx, val); } + if lv.is_mem { + val = load_if_immediate(bcx, val, e_ty); + } + bcx = copy_ty(bcx, val, e_ty).bcx; + add_clean_temp(bcx, val, e_ty); } } else if type_is_immediate(ccx, e_ty) && !lv.is_mem { val = do_spill(bcx, val); @@ -4620,13 +4605,14 @@ fn trans_args(cx: &@block_ctxt, llenv: ValueRef, to_revoke: to_revoke}; } -fn trans_call(cx: &@block_ctxt, f: &@ast::expr, +fn trans_call(in_cx: &@block_ctxt, f: &@ast::expr, lliterbody: &option::t, args: &[@ast::expr], id: ast::node_id) -> result { // NB: 'f' isn't necessarily a function; it might be an entire self-call // expression because of the hack that allows us to process self-calls // with trans_call. - + let cx = new_scope_block_ctxt(in_cx, "call"); + in_cx.build.Br(cx.llbb); let f_res = trans_lval_gen(cx, f); let fn_ty: ty::t; alt f_res.method_ty { @@ -4691,7 +4677,7 @@ fn trans_call(cx: &@block_ctxt, f: &@ast::expr, // Retval doesn't correspond to anything really tangible // in the frame, but it's a ref all the same, so we put a // note here to drop it when we're done in this scope. - add_clean_temp(cx, retval, ret_ty); + add_clean_temp(in_cx, retval, ret_ty); } } some(_) { @@ -4705,7 +4691,13 @@ fn trans_call(cx: &@block_ctxt, f: &@ast::expr, for {v: v, t: t}: {v: ValueRef, t: ty::t} in args_res.to_zero { zero_alloca(bcx, v, t) } - for v: ValueRef in args_res.to_revoke { revoke_clean(bcx, v) } + for v: ValueRef in args_res.to_revoke { + revoke_clean(bcx, v) + } + bcx = trans_block_cleanups(bcx, cx); + let next_cx = new_sub_block_ctxt(in_cx, "next"); + bcx.build.Br(next_cx.llbb); + bcx = next_cx; } ret rslt(bcx, retval); } @@ -5230,7 +5222,9 @@ fn trans_fail_value(cx: &@block_ctxt, sp_opt: &option::t, ret rslt(cx, C_nil()); } -fn trans_put(cx: &@block_ctxt, e: &option::t<@ast::expr>) -> result { +fn trans_put(in_cx: &@block_ctxt, e: &option::t<@ast::expr>) -> result { + let cx = new_scope_block_ctxt(in_cx, "put"); + in_cx.build.Br(cx.llbb); let llcallee = C_nil(); let llenv = C_nil(); alt { cx.fcx.lliterbody } { @@ -5260,7 +5254,10 @@ fn trans_put(cx: &@block_ctxt, e: &option::t<@ast::expr>) -> result { } } bcx.build.FastCall(llcallee, llargs); - ret rslt(bcx, C_nil()); + bcx = trans_block_cleanups(bcx, cx); + let next_cx = new_sub_block_ctxt(in_cx, "next"); + bcx.build.Br(next_cx.llbb); + ret rslt(next_cx, C_nil()); } fn trans_uniq(cx: &@block_ctxt, contents: &@ast::expr) -> lval_result { @@ -5817,57 +5814,40 @@ fn create_llargs_for_fn_args(cx: &@fn_ctxt, proto: ast::proto, } } -fn copy_args_to_allocas(fcx: @fn_ctxt, args: &[ast::arg], - arg_tys: &[ty::arg]) { +fn copy_args_to_allocas(fcx: @fn_ctxt, scope: @block_ctxt, + args: &[ast::arg], arg_tys: &[ty::arg]) { let bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs); let arg_n: uint = 0u; for aarg: ast::arg in args { - if aarg.mode == ast::val { - let argval, arg_ty = arg_tys.(arg_n).ty; - alt bcx.fcx.llargs.find(aarg.id) { - some(x) { argval = x; } - _ { - bcx_ccx(bcx).sess.span_fatal( - aarg.ty.span, - "unbound arg ID in copy_args_to_allocas"); - } - } - let a; - if ty::type_is_structural(fcx_tcx(fcx), arg_ty) { - a = alloca(bcx, llvm::LLVMGetElementType(val_ty(argval))); - bcx = memmove_ty(bcx, a, argval, arg_ty).bcx; - } else { - a = do_spill(bcx, argval); - } + let arg_ty = arg_tys[arg_n].ty; + alt aarg.mode { + ast::val. { + // Structural types are passed by pointer, and we use the + // pointed-to memory for the local. + if !ty::type_is_structural(fcx_tcx(fcx), arg_ty) { + // Overwrite the llargs entry for this arg with its alloca. + let aval = bcx.fcx.llargs.get(aarg.id); + let addr = do_spill(bcx, aval); + bcx.fcx.llargs.insert(aarg.id, addr); - // Overwrite the llargs entry for this arg with its alloca. - bcx.fcx.llargs.insert(aarg.id, a); + // Args that are locally assigned to need to do a local + // take/drop + if fcx.lcx.ccx.mut_map.contains_key(aarg.id) { + bcx = copy_ty(bcx, aval, arg_ty).bcx; + add_clean(scope, addr, arg_ty); + } + } + } + ast::move. { + add_clean(scope, bcx.fcx.llargs.get(aarg.id), arg_ty); + } + _ {} } arg_n += 1u; } fcx.llcopyargs = bcx.llbb; } -fn add_cleanups_for_args(bcx: &@block_ctxt, args: &[ast::arg], - arg_tys: &[ty::arg]) { - let arg_n: uint = 0u; - for aarg: ast::arg in args { - if aarg.mode == ast::val || aarg.mode == ast::move { - let argval; - alt bcx.fcx.llargs.find(aarg.id) { - some(x) { argval = x; } - _ { - bcx_ccx(bcx).sess.span_fatal( - aarg.ty.span, - "unbound arg ID in add_cleanups_for_args"); - } - } - add_clean(bcx, argval, arg_tys[arg_n].ty); - } - arg_n += 1u; - } -} - fn is_terminated(cx: &@block_ctxt) -> bool { let inst = llvm::LLVMGetLastInstruction(cx.llbb); ret llvm::LLVMIsATerminatorInst(inst) as int != 0; @@ -5964,8 +5944,15 @@ fn trans_closure(bcx_maybe: &option::t<@block_ctxt>, some(llself) { populate_fn_ctxt_from_llself(fcx, llself); } _ { } } + + // Create the first basic block in the function and keep a handle on it to + // pass to finish_fn later. + let bcx = new_top_block_ctxt(fcx); + let lltop = bcx.llbb; + let block_ty = node_id_type(cx.ccx, f.body.node.id); + let arg_tys = arg_tys_of_fn(fcx.lcx.ccx, id); - copy_args_to_allocas(fcx, f.decl.inputs, arg_tys); + copy_args_to_allocas(fcx, bcx, f.decl.inputs, arg_tys); // Figure out if we need to build a closure and act accordingly let res = @@ -5989,12 +5976,6 @@ fn trans_closure(bcx_maybe: &option::t<@block_ctxt>, _ { none } }; - // Create the first basic block in the function and keep a handle on it to - // pass to finish_fn later. - let bcx = new_top_block_ctxt(fcx); - add_cleanups_for_args(bcx, f.decl.inputs, arg_tys); - let lltop = bcx.llbb; - let block_ty = node_id_type(cx.ccx, f.body.node.id); // This call to trans_block is the place where we bridge between // translation calls that don't have a return value (trans_crate, @@ -6119,8 +6100,8 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id, i += 1u; } let arg_tys = arg_tys_of_fn(cx.ccx, variant.node.id); - copy_args_to_allocas(fcx, fn_args, arg_tys); let bcx = new_top_block_ctxt(fcx); + copy_args_to_allocas(fcx, bcx, fn_args, arg_tys); let lltop = bcx.llbb; // Cast the tag to a type we can GEP into. @@ -6333,16 +6314,12 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span, main_llfn: ValueRef, let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u); let llenvarg = llvm::LLVMGetParam(llfdecl, 2u); let llargvarg = llvm::LLVMGetParam(llfdecl, 3u); - let args = if takes_ivec { - ~[lloutputarg, lltaskarg, llenvarg, llargvarg] - } else { - // If the crate's main function doesn't take the args vector then - // we're responsible for freeing it - bcx = maybe_free_ivec_heap_part(bcx, llargvarg, - ty::mk_str(ccx.tcx)).bcx; - ~[lloutputarg, lltaskarg, llenvarg] - }; + let args = [lloutputarg, lltaskarg, llenvarg]; + if takes_ivec { args += [llargvarg]; } bcx.build.FastCall(main_llfn, args); + // We're responsible for freeing the arg vector + bcx = maybe_free_ivec_heap_part(bcx, llargvarg, + ty::mk_str(ccx.tcx)).bcx; build_return(bcx); finish_fn(fcx, lltop); @@ -6555,7 +6532,6 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str], let args = ty::ty_fn_args(ccx.tcx, fn_type); // Build up the list of arguments. - let drop_args: [{val: ValueRef, ty: ty::t}] = []; let i = arg_n; for arg: ty::arg in args { let llarg = llvm::LLVMGetParam(fcx.llfn, i); @@ -6564,7 +6540,6 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str], let llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode); call_args += [llarg_i32]; } else { call_args += [llarg]; } - if arg.mode == ty::mo_val { drop_args += [{val: llarg, ty: arg.ty}]; } i += 1u; } let r; @@ -6594,9 +6569,8 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str], rptr = result.rptr; } _ { - r = - trans_native_call(bcx.build, ccx.externs, ccx.llmod, name, - call_args); + r = trans_native_call(bcx.build, ccx.externs, + ccx.llmod, name, call_args); rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32())); } } @@ -6606,9 +6580,6 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str], if !rty_is_nil && !uses_retptr { bcx.build.Store(r, rptr); } - for d: {val: ValueRef, ty: ty::t} in drop_args { - bcx = drop_ty(bcx, d.val, d.ty).bcx; - } build_return(bcx); finish_fn(fcx, lltop); } @@ -6927,7 +6898,8 @@ fn write_abi_version(ccx: &@crate_ctxt) { } fn trans_crate(sess: &session::session, crate: &@ast::crate, tcx: &ty::ctxt, - output: &str, amap: &ast_map::map) -> ModuleRef { + output: &str, amap: &ast_map::map, mut_map: alias::mut_map) + -> ModuleRef { let llmod = llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"), llvm::LLVMGetGlobalContext()); @@ -6979,6 +6951,7 @@ fn trans_crate(sess: &session::session, crate: &@ast::crate, tcx: &ty::ctxt, type_sha1s: sha1s, type_short_names: short_names, tcx: tcx, + mut_map: mut_map, stats: {mutable n_static_tydescs: 0u, mutable n_derived_tydescs: 0u, diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index e53f4a47b272..bf7a03cdbf11 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -142,6 +142,7 @@ type crate_ctxt = type_sha1s: hashmap, type_short_names: hashmap, tcx: ty::ctxt, + mut_map: alias::mut_map, stats: stats, upcalls: @upcall::upcalls, rust_object_type: TypeRef, diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index 06094808fad9..5bbd281ef485 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -50,17 +50,17 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj, } let fcx = new_fn_ctxt(cx, sp, llctor_decl); + // Create the first block context in the function and keep a handle on it + // to pass to finish_fn later. + let bcx = new_top_block_ctxt(fcx); + let lltop = bcx.llbb; + // Both regular arguments and type parameters are handled here. create_llargs_for_fn_args(fcx, ast::proto_fn, none::, ty::ret_ty_of_fn(ccx.tcx, ctor_id), fn_args, ty_params); let arg_tys: [ty::arg] = arg_tys_of_fn(ccx, ctor_id); - copy_args_to_allocas(fcx, fn_args, arg_tys); - - // Create the first block context in the function and keep a handle on it - // to pass to finish_fn later. - let bcx = new_top_block_ctxt(fcx); - let lltop = bcx.llbb; + copy_args_to_allocas(fcx, bcx, fn_args, arg_tys); // Pick up the type of this object by looking at our own output type, that // is, the output type of the object constructor we're building. diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index b781a2481c24..ef04e66d756a 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -334,7 +334,6 @@ fn noop_fold_expr(e: &expr_, fld: ast_fold) -> expr_ { let fold_mac = bind fold_mac_(_, fld); - ret alt e { expr_vec(exprs, mut) { expr_vec(fld.map_exprs(fld.fold_expr, exprs), mut) diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 8cf53edbc9d5..d20f345b3aff 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1081,7 +1081,8 @@ fn parse_dot_or_call_expr_with(p: &parser, e: @ast::expr) -> @ast::expr { parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_expr, p); hi = es.span.hi; - e = mk_expr(p, lo, hi, ast::expr_call(e, es.node)); + let nd = ast::expr_call(e, es.node); + e = mk_expr(p, lo, hi, nd); } } token::LBRACKET. { diff --git a/src/test/run-pass/export-unexported-dep.rs b/src/test/run-pass/export-unexported-dep.rs index bc8451a4854c..357821ac34ea 100644 --- a/src/test/run-pass/export-unexported-dep.rs +++ b/src/test/run-pass/export-unexported-dep.rs @@ -6,7 +6,7 @@ mod foo { export g; // not exported - tag t { t1; } + tag t { t1; t2; } fn f() -> t { ret t1; }