diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index cf671bdce6776..3939bbaa488ea 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -996,13 +996,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 = push_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 = push_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; } @@ -1527,7 +1527,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); @@ -1566,7 +1566,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut 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, llenv: unsafe { @@ -1672,7 +1672,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, match fcx.llself { Some(slf) => { let self_val = if slf.is_copy - && datum::appropriate_mode(slf.t).is_by_value() { + && datum::appropriate_mode(bcx.tcx(), slf.t).is_by_value() { let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t)); let alloc = alloc_ty(bcx, slf.t); Store(bcx, tmp, alloc); @@ -1700,7 +1700,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 41f1d0e61e53d..05fe0bed3b696 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -633,7 +633,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) { llargs.push(llretslot); } @@ -680,7 +680,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); @@ -694,7 +694,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); } } @@ -898,7 +898,7 @@ pub fn trans_arg_expr(bcx: block, } ty::ByCopy => { if ty::type_needs_drop(bcx.tcx(), arg_datum.ty) || - arg_datum.appropriate_mode().is_by_ref() { + arg_datum.appropriate_mode(bcx.tcx()).is_by_ref() { debug!("by copy arg with type %s, storing to scratch", bcx.ty_to_str(arg_datum.ty)); let scratch = scratch_datum(bcx, arg_datum.ty, false); @@ -914,7 +914,7 @@ pub fn trans_arg_expr(bcx: block, scratch.add_clean(bcx); temp_cleanups.push(scratch.val); - match scratch.appropriate_mode() { + match scratch.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 0fe3dfe80c8c9..8ee4b6644cbe9 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -188,7 +188,7 @@ pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum { Datum { val: scratch, ty: ty, mode: ByRef(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, @@ -197,7 +197,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(RevokeClean) @@ -508,10 +508,10 @@ impl Datum { } } - pub fn appropriate_mode(&self) -> DatumMode { + pub fn appropriate_mode(&self, tcx: ty::ctxt) -> DatumMode { /*! See the `appropriate_mode()` function */ - appropriate_mode(self.ty) + appropriate_mode(tcx, self.ty) } pub fn to_appropriate_llval(&self, bcx: block) -> ValueRef { @@ -519,7 +519,7 @@ 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) } @@ -530,7 +530,7 @@ 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) } @@ -657,13 +657,7 @@ 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) } }; @@ -695,15 +689,15 @@ 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)); - (Some(Datum {ty: ty, ..*self}), bcx) + assert!(ty::type_is_immediate(bcx.tcx(), ty)); + ( + Some(Datum { + val: ExtractValue(bcx, self.val, 0), + ty: ty, + mode: ByValue + }), + bcx + ) } } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 1511f25414071..d07c2b736c47e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -291,7 +291,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 c01f01db5fd15..76dc7e1138149 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -103,7 +103,7 @@ fn foreign_signature(ccx: &mut 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), } } @@ -192,7 +192,7 @@ fn build_wrap_fn_(ccx: @mut 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)); @@ -648,7 +648,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, // intrinsics, there are no argument cleanups 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}; bcx = src.move_to(bcx, DROP_EXISTING, @@ -657,7 +657,7 @@ pub fn trans_intrinsic(ccx: @mut 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}; bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg)); @@ -731,7 +731,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let lldestptr = PointerCast(bcx, lldestptr, Type::i8p()); 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 @@ -1221,7 +1221,7 @@ pub fn trans_foreign_fn(ccx: @mut 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(bcx.tcx(), tys.fn_sig.output) { let llretptr = load_inbounds(bcx, llargbundle, [0u, n]); llargvals.push(llretptr); } @@ -1247,7 +1247,8 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, shim_types: &ShimTypes, llargbundle: ValueRef, llretval: ValueRef) { - if bcx.fcx.llretptr.is_some() && ty::type_is_immediate(shim_types.fn_sig.output) { + if bcx.fcx.llretptr.is_some() && + 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/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 4ae8554d7143c..51943b9aad9f2 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -357,7 +357,7 @@ pub fn make_mono_id(ccx: @mut CrateContext, let llty = type_of::type_of(ccx, subst); let size = machine::llbitsize_of_real(ccx, llty); let align = machine::llalign_of_min(ccx, llty); - let mode = datum::appropriate_mode(subst); + let mode = datum::appropriate_mode(ccx.tcx, subst); let data_class = mono_data_classify(subst); debug!("make_mono_id: type %s -> size %u align %u mode %? class %?", diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 481f08ee192dd..562a8fd69b62d 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -18,8 +18,8 @@ use middle::trans::type_::Type; 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: &mut CrateContext, arg_ty: &ty::t) -> Type { @@ -41,7 +41,7 @@ pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Typ // 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(lloutputtype.ptr_to()); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4ed21d73f3e78..caf5ff5d14927 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1647,9 +1647,22 @@ pub fn type_is_scalar(ty: t) -> bool { } } -pub fn type_is_immediate(ty: t) -> bool { +fn type_is_newtype_immediate(cx: ctxt, ty: t) -> bool { + match get(ty).sty { + ty_struct(def_id, ref substs) => { + let fields = struct_fields(cx, def_id, substs); + fields.len() == 1 && + fields[0].ident == token::special_idents::unnamed_field && + type_is_immediate(cx, fields[0].mt.ty) + } + _ => false + } +} + +pub fn type_is_immediate(cx: ctxt, ty: t) -> bool { return type_is_scalar(ty) || type_is_boxed(ty) || - type_is_unique(ty) || type_is_region_ptr(ty); + type_is_unique(ty) || type_is_region_ptr(ty) || + type_is_newtype_immediate(cx, ty); } pub fn type_needs_drop(cx: ctxt, ty: t) -> bool { @@ -3148,7 +3161,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/newtype-temporary.rs b/src/test/run-pass/newtype-temporary.rs new file mode 100644 index 0000000000000..d2407f3d6059b --- /dev/null +++ b/src/test/run-pass/newtype-temporary.rs @@ -0,0 +1,19 @@ +// 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. + +struct Foo(uint); + +fn foo() -> Foo { + Foo(42) +} + +fn main() { + assert_eq!(*foo(), 42); +}