diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 66cca74214a41..7271d65875b4b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1034,13 +1034,13 @@ pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef { pub fn spill_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef { let _icx = cx.insn_ctxt("spill_if_immediate"); - if ty::type_is_immediate(t) { return do_spill(cx, v, t); } + if ty::type_is_immediate(cx.tcx(), t) { return do_spill(cx, v, t); } return v; } pub fn load_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef { let _icx = cx.insn_ctxt("load_if_immediate"); - if ty::type_is_immediate(t) { return Load(cx, v); } + if ty::type_is_immediate(cx.tcx(), t) { return Load(cx, v); } return v; } @@ -1571,7 +1571,7 @@ pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks { // slot where the return value of the function must go. pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef { unsafe { - if !ty::type_is_immediate(output_type) { + if !ty::type_is_immediate(fcx.ccx.tcx, output_type) { llvm::LLVMGetParam(fcx.llfn, 0) } else { let lloutputtype = type_of::type_of(*fcx.ccx, output_type); @@ -1612,7 +1612,7 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext, ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type) } }; - let is_immediate = ty::type_is_immediate(substd_output_type); + let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type); let fcx = @mut fn_ctxt_ { llfn: llfndecl, @@ -1732,7 +1732,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, // This alloca should be optimized away by LLVM's mem-to-reg pass in // the event it's not truly needed. // only by value if immediate: - let llarg = if datum::appropriate_mode(arg_ty).is_by_value() { + let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() { let alloc = alloc_ty(bcx, arg_ty); Store(bcx, raw_llarg, alloc); alloc diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 382e80148ec01..d7a5afec1ae41 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -486,8 +486,22 @@ pub fn trans_call_inner(in_cx: block, } Method(d) => { // Weird but true: we pass self in the *environment* slot! + let llselfptr = + if ty::type_is_immediate(bcx.tcx(), d.self_ty) && + d.self_mode != ty::ByRef && + llvm::LLVMGetTypeKind(val_ty(d.llself)) != lib::llvm::Pointer { + + let llselfptr = alloca(bcx, val_ty(d.llself)); + + Store(bcx, d.llself, llselfptr); + bcx = glue::drop_ty(bcx, llselfptr, d.self_ty); + + llselfptr + } else { + d.llself + }; let llself = PointerCast(bcx, - d.llself, + llselfptr, T_opaque_box_ptr(ccx)); (d.llfn, llself) } @@ -508,7 +522,7 @@ pub fn trans_call_inner(in_cx: block, let mut llargs = ~[]; - if ty::type_is_immediate(ret_ty) { + if ty::type_is_immediate(bcx.tcx(), ret_ty) { unsafe { llargs.push(llvm::LLVMGetUndef(T_ptr(T_i8()))); } @@ -557,7 +571,7 @@ pub fn trans_call_inner(in_cx: block, // case to ignore instead of invoking the Store // below into a scratch pointer of a mismatched // type. - } else if ty::type_is_immediate(ret_ty) { + } else if ty::type_is_immediate(bcx.tcx(), ret_ty) { let llscratchptr = alloc_ty(bcx, ret_ty); Store(bcx, llresult, llscratchptr); bcx = glue::drop_ty(bcx, llscratchptr, ret_ty); @@ -571,7 +585,7 @@ pub fn trans_call_inner(in_cx: block, // If this is an immediate, store into the result location. // (If this was not an immediate, the result will already be // directly written into the output slot.) - if ty::type_is_immediate(ret_ty) { + if ty::type_is_immediate(bcx.tcx(), ret_ty) { Store(bcx, llresult, lldest); } } @@ -775,7 +789,7 @@ pub fn trans_arg_expr(bcx: block, scratch.add_clean(bcx); temp_cleanups.push(scratch.val); - match arg_datum.appropriate_mode() { + match arg_datum.appropriate_mode(bcx.tcx()) { ByValue => val = Load(bcx, scratch.val), ByRef => val = scratch.val, } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 4a9a907d5b7c0..718e4de286264 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -195,7 +195,7 @@ pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum { Datum { val: scratch, ty: ty, mode: ByRef, source: RevokeClean } } -pub fn appropriate_mode(ty: ty::t) -> DatumMode { +pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode { /*! * * Indicates the "appropriate" mode for this value, @@ -204,7 +204,7 @@ pub fn appropriate_mode(ty: ty::t) -> DatumMode { if ty::type_is_nil(ty) || ty::type_is_bot(ty) { ByValue - } else if ty::type_is_immediate(ty) { + } else if ty::type_is_immediate(tcx, ty) { ByValue } else { ByRef @@ -474,10 +474,10 @@ pub impl Datum { } } - fn appropriate_mode(&self) -> DatumMode { + fn appropriate_mode(&self, tcx: ty::ctxt) -> DatumMode { /*! See the `appropriate_mode()` function */ - appropriate_mode(self.ty) + appropriate_mode(tcx, self.ty) } fn to_appropriate_llval(&self, bcx: block) -> ValueRef { @@ -485,7 +485,7 @@ pub impl Datum { * * Yields an llvalue with the `appropriate_mode()`. */ - match self.appropriate_mode() { + match self.appropriate_mode(bcx.tcx()) { ByValue => self.to_value_llval(bcx), ByRef => self.to_ref_llval(bcx) } @@ -496,7 +496,7 @@ pub impl Datum { * * Yields a datum with the `appropriate_mode()`. */ - match self.appropriate_mode() { + match self.appropriate_mode(bcx.tcx()) { ByValue => self.to_value_datum(bcx), ByRef => self.to_ref_datum(bcx) } @@ -620,13 +620,7 @@ pub impl Datum { 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)); + assert!(ty::type_is_immediate(bcx.tcx(), ty)); (Some(Datum {ty: ty, ..*self}), bcx) } }; @@ -659,14 +653,7 @@ pub impl Datum { ) } 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)); + assert!(ty::type_is_immediate(bcx.tcx(), ty)); (Some(Datum {ty: ty, ..*self}), bcx) } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 8883cc44d1213..e9c688b94d3df 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -287,7 +287,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx)); let scratch = scratch_datum(bcx, closure_ty, false); let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]); - assert_eq!(datum.appropriate_mode(), ByValue); + assert_eq!(datum.appropriate_mode(tcx), ByValue); Store(bcx, datum.to_appropriate_llval(bcx), llfn); let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]); Store(bcx, base::null_env_ptr(bcx), llenv); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 13d8f854fb20f..3c24de2ed18f5 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -99,7 +99,7 @@ fn foreign_signature(ccx: @CrateContext, fn_sig: &ty::FnSig) LlvmSignature { llarg_tys: llarg_tys, llret_ty: llret_ty, - sret: !ty::type_is_immediate(fn_sig.output), + sret: !ty::type_is_immediate(ccx.tcx, fn_sig.output), } } @@ -191,7 +191,7 @@ fn build_wrap_fn_(ccx: @CrateContext, // Patch up the return type if it's not immediate and we're returning via // the C ABI. - if needs_c_return && !ty::type_is_immediate(tys.fn_sig.output) { + if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) { let lloutputtype = type_of::type_of(*fcx.ccx, tys.fn_sig.output); fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype)); @@ -695,7 +695,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, // is not necessary since, for intrinsics, there is no // cleanup to concern ourselves with. let tp_ty = substs.tys[0]; - let mode = appropriate_mode(tp_ty); + let mode = appropriate_mode(ccx.tcx, tp_ty); let src = Datum {val: get_param(decl, first_real_arg + 1u), ty: tp_ty, mode: mode, source: RevokeClean}; bcx = src.move_to(bcx, DROP_EXISTING, @@ -704,7 +704,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, ~"move_val_init" => { // See comments for `"move_val"`. let tp_ty = substs.tys[0]; - let mode = appropriate_mode(tp_ty); + let mode = appropriate_mode(ccx.tcx, tp_ty); let src = Datum {val: get_param(decl, first_real_arg + 1u), ty: tp_ty, mode: mode, source: RevokeClean}; bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg)); @@ -775,7 +775,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, let lldestptr = PointerCast(bcx, lldestptr, T_ptr(T_i8())); let llsrcval = get_param(decl, first_real_arg); - let llsrcptr = if ty::type_is_immediate(in_type) { + let llsrcptr = if ty::type_is_immediate(ccx.tcx, in_type) { let llsrcptr = alloca(bcx, llintype); Store(bcx, llsrcval, llsrcptr); llsrcptr @@ -1206,7 +1206,7 @@ pub fn trans_foreign_fn(ccx: @CrateContext, let mut i = 0u; let n = tys.fn_sig.inputs.len(); - if !ty::type_is_immediate(tys.fn_sig.output) { + if !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) { let llretptr = load_inbounds(bcx, llargbundle, ~[0u, n]); llargvals.push(llretptr); } else { @@ -1234,7 +1234,7 @@ pub fn trans_foreign_fn(ccx: @CrateContext, shim_types: &ShimTypes, llargbundle: ValueRef, llretval: ValueRef) { - if ty::type_is_immediate(shim_types.fn_sig.output) { + if ty::type_is_immediate(bcx.tcx(), shim_types.fn_sig.output) { // Write the value into the argument bundle. let arg_count = shim_types.fn_sig.inputs.len(); let llretptr = load_inbounds(bcx, diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index f77e2e0d52aa2..366c1a58052d0 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -100,6 +100,15 @@ pub fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { ty::ty_estr(ty::vstore_box) => { decr_refcnt_maybe_free(bcx, v, t) } + ty::ty_struct(def_id, ref substs) => { + let fields = ty::struct_fields(bcx.tcx(), def_id, substs); + + if fields.len() == 1 { + drop_ty_immediate(bcx, v, fields[0].mt.ty) + } else { + bcx.tcx().sess.bug(~"drop_ty_immediate: non-box ty") + } + } _ => bcx.tcx().sess.bug(~"drop_ty_immediate: non-box ty") } } @@ -120,6 +129,15 @@ pub fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> Result { ty::ty_estr(ty::vstore_uniq) => { tvec::duplicate_uniq(bcx, v, t) } + ty::ty_struct(def_id, ref substs) => { + let fields = ty::struct_fields(bcx.tcx(), def_id, substs); + + if fields.len() == 1 { + take_ty_immediate(bcx, v, fields[0].mt.ty) + } else { + rslt(bcx, v) + } + } _ => rslt(bcx, v) } } @@ -147,6 +165,15 @@ pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { Store(bcx, v, vp); free_ty(bcx, vp, t) } + ty::ty_struct(def_id, ref substs) => { + let fields = ty::struct_fields(bcx.tcx(), def_id, substs); + + if fields.len() == 1 { + free_ty_immediate(bcx, v, fields[0].mt.ty) + } else { + bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty") + } + } _ => bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty") } } @@ -641,7 +668,7 @@ pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) { pub fn declare_tydesc_addrspace(ccx: @CrateContext, t: ty::t) -> addrspace { if !ty::type_needs_drop(ccx.tcx, t) { return default_addrspace; - } else if ty::type_is_immediate(t) { + } else if ty::type_is_immediate(ccx.tcx, t) { // For immediate types, we don't actually need an addrspace, because // e.g. boxed types include pointers to their contents which are // already correctly tagged with addrspaces. diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 40b92d336536c..470077dcd233f 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -378,7 +378,7 @@ pub fn make_mono_id(ccx: @CrateContext, let llty = type_of::type_of(ccx, subst); let size = machine::llbitsize_of_real(ccx, llty); let align = machine::llalign_of_pref(ccx, llty); - let mode = datum::appropriate_mode(subst); + let mode = datum::appropriate_mode(ccx.tcx, subst); let data_class = mono_data_classify(subst); // Special value for nil to prevent problems diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 8d5721aeb6512..a9126cb136ac3 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -19,8 +19,8 @@ use util::ppaux; use syntax::ast; -pub fn arg_is_indirect(_: @CrateContext, arg_ty: &ty::t) -> bool { - !ty::type_is_immediate(*arg_ty) +pub fn arg_is_indirect(ccx: @CrateContext, arg_ty: &ty::t) -> bool { + !ty::type_is_immediate(ccx.tcx, *arg_ty) } pub fn type_of_explicit_arg(ccx: @CrateContext, arg_ty: &ty::t) -> TypeRef { @@ -40,7 +40,7 @@ pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::t], output: ty::t) // Arg 0: Output pointer. // (if the output type is non-immediate) - let output_is_immediate = ty::type_is_immediate(output); + let output_is_immediate = ty::type_is_immediate(cx.tcx, output); let lloutputtype = type_of(cx, output); if !output_is_immediate { atys.push(T_ptr(lloutputtype)); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1a2a84ceae856..a2ca6390e5e99 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1689,9 +1689,21 @@ pub fn type_is_scalar(ty: t) -> bool { } } -pub fn type_is_immediate(ty: t) -> bool { - return type_is_scalar(ty) || type_is_boxed(ty) || - type_is_unique(ty) || type_is_region_ptr(ty); +pub fn type_is_newtype_scalar(cx: ctxt, ty: t) -> bool { + match get(ty).sty { + ty_struct(def_id, ref substs) => { + let fields = struct_fields(cx, def_id, substs); + + // Is this a newtype/single field scalar struct? + fields.len() == 1 && type_is_scalar(fields[0].mt.ty) + } + _ => false + } +} + +pub fn type_is_immediate(cx: ctxt, ty: t) -> bool { + return type_is_newtype_scalar(cx, ty) || type_is_scalar(ty) || + type_is_boxed(ty) || type_is_unique(ty) || type_is_region_ptr(ty); } pub fn type_needs_drop(cx: ctxt, ty: t) -> bool { @@ -3215,7 +3227,7 @@ pub fn expr_kind(tcx: ctxt, ast::expr_cast(*) => { match tcx.node_types.find(&(expr.id as uint)) { Some(&t) => { - if ty::type_is_immediate(t) { + if ty::type_is_immediate(tcx, t) { RvalueDatumExpr } else { RvalueDpsExpr diff --git a/src/test/run-pass/issue-3559 b/src/test/run-pass/issue-3559 deleted file mode 100755 index 505b9b65512f2..0000000000000 Binary files a/src/test/run-pass/issue-3559 and /dev/null differ diff --git a/src/test/run-pass/issue-3702 b/src/test/run-pass/issue-3702 deleted file mode 100755 index 3f39ee314421b..0000000000000 Binary files a/src/test/run-pass/issue-3702 and /dev/null differ diff --git a/src/test/run-pass/issue-4016 b/src/test/run-pass/issue-4016 deleted file mode 100755 index ff979383c1020..0000000000000 Binary files a/src/test/run-pass/issue-4016 and /dev/null differ diff --git a/src/test/run-pass/issue-4092 b/src/test/run-pass/issue-4092 deleted file mode 100755 index 761b6ab468624..0000000000000 Binary files a/src/test/run-pass/issue-4092 and /dev/null differ diff --git a/src/test/run-pass/issue-5321-immediates-with-bare-self.rs b/src/test/run-pass/issue-5321-immediates-with-bare-self.rs new file mode 100644 index 0000000000000..d60cd89c884c3 --- /dev/null +++ b/src/test/run-pass/issue-5321-immediates-with-bare-self.rs @@ -0,0 +1,35 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Fooable { + fn yes(self); +} + +impl Fooable for uint { + fn yes(self) { + for self.times { + io::println("yes"); + } + } +} + +struct Bar(uint); +impl Fooable for Bar { + fn yes(self) { + for self.times { + io::println("yes"); + } + } +} + +fn main() { + 2.yes(); + Bar(2).yes(); +}