about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-03 23:31:56 -0700
committerbors <bors@rust-lang.org>2013-07-03 23:31:56 -0700
commite07e9bbf3698c7e1491129f58cb02858dde96337 (patch)
treead507e6f7c7031b968f371f77a4ec1f0c45598e7
parentdd4f6bb2a2e0fe4f2f417b99301b44d12567c243 (diff)
parent8aa26ad4547007996e1c3c0f1aa941ea8689b5a6 (diff)
downloadrust-e07e9bbf3698c7e1491129f58cb02858dde96337.tar.gz
rust-e07e9bbf3698c7e1491129f58cb02858dde96337.zip
auto merge of #7543 : sanxiyn/rust/newtype-immediates, r=catamorphism
Fix #6612. Rebase of #6725. Fixed an additional bug and added a test.
-rw-r--r--src/librustc/middle/trans/base.rs12
-rw-r--r--src/librustc/middle/trans/callee.rs10
-rw-r--r--src/librustc/middle/trans/datum.rs38
-rw-r--r--src/librustc/middle/trans/expr.rs2
-rw-r--r--src/librustc/middle/trans/foreign.rs15
-rw-r--r--src/librustc/middle/trans/monomorphize.rs2
-rw-r--r--src/librustc/middle/trans/type_of.rs6
-rw-r--r--src/librustc/middle/ty.rs19
-rw-r--r--src/test/run-pass/newtype-temporary.rs19
9 files changed, 75 insertions, 48 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index d598a6fbcf9..d6105cc1dde 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1014,13 +1014,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;
 }
 
@@ -1545,7 +1545,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);
@@ -1584,7 +1584,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 {
@@ -1690,7 +1690,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);
@@ -1718,7 +1718,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 41f1d0e61e5..05fe0bed3b6 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 0fe3dfe80c8..8ee4b6644cb 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 df197ded629..9c831db514a 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 0a3b6d881e4..36568192454 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 ad48c30747e..3bd483591c2 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -356,7 +356,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 481f08ee192..562a8fd69b6 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 0beb2b3f64d..2cb66ac8b02 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1646,9 +1646,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 {
@@ -3147,7 +3160,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 00000000000..d2407f3d605
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
+}