about summary refs log tree commit diff
path: root/src/librustc_trans/trans/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_trans/trans/expr.rs')
-rw-r--r--src/librustc_trans/trans/expr.rs433
1 files changed, 223 insertions, 210 deletions
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 44d8457c316..480679f43cb 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -54,6 +54,7 @@ use self::lazy_binop_ty::*;
 
 use back::abi;
 use llvm::{self, ValueRef};
+use middle::check_const;
 use middle::def;
 use middle::mem_categorization::Typer;
 use middle::subst::{self, Substs};
@@ -68,7 +69,6 @@ use trans::glue;
 use trans::machine;
 use trans::meth;
 use trans::monomorphize;
-use trans::inline;
 use trans::tvec;
 use trans::type_of;
 use middle::ty::{struct_fields, tup_fields};
@@ -84,8 +84,9 @@ use trans::type_::Type;
 use syntax::{ast, ast_util, codemap};
 use syntax::ptr::P;
 use syntax::parse::token;
-use std::rc::Rc;
 use std::iter::repeat;
+use std::mem;
+use std::rc::Rc;
 
 // Destinations
 
@@ -115,11 +116,56 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                               -> Block<'blk, 'tcx> {
     let mut bcx = bcx;
 
+    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
+
     if bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
         // use trans, which may be less efficient but
         // which will perform the adjustments:
         let datum = unpack_datum!(bcx, trans(bcx, expr));
-        return datum.store_to_dest(bcx, dest, expr.id)
+        return datum.store_to_dest(bcx, dest, expr.id);
+    }
+
+    let qualif = bcx.tcx().const_qualif_map.borrow()[expr.id];
+    if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) {
+        if !qualif.intersects(check_const::PREFER_IN_PLACE) {
+            if let SaveIn(lldest) = dest {
+                let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
+                                                            bcx.fcx.param_substs);
+                // Cast pointer to destination, because constants
+                // have different types.
+                let lldest = PointerCast(bcx, lldest, val_ty(global));
+                memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
+            }
+            // Don't do anything in the Ignore case, consts don't need drop.
+            return bcx;
+        } else {
+            // The only way we're going to see a `const` at this point is if
+            // it prefers in-place instantiation, likely because it contains
+            // `[x; N]` somewhere within.
+            match expr.node {
+                ast::ExprPath(_) | ast::ExprQPath(_) => {
+                    match bcx.def(expr.id) {
+                        def::DefConst(did) => {
+                            let expr = consts::get_const_expr(bcx.ccx(), did, expr);
+                            // Temporarily get cleanup scopes out of the way,
+                            // as they require sub-expressions to be contained
+                            // inside the current AST scope.
+                            // These should record no cleanups anyways, `const`
+                            // can't have destructors.
+                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
+                                                      vec![]);
+                            bcx = trans_into(bcx, expr, dest);
+                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
+                                                      scopes);
+                            assert!(scopes.is_empty());
+                            return bcx;
+                        }
+                        _ => {}
+                    }
+                }
+                _ => {}
+            }
+        }
     }
 
     debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
@@ -130,7 +176,6 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                                           false);
     bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
 
-    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
     let kind = ty::expr_kind(bcx.tcx(), expr);
     bcx = match kind {
         ty::LvalueExpr | ty::RvalueDatumExpr => {
@@ -157,14 +202,70 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let mut bcx = bcx;
     let fcx = bcx.fcx;
+    let qualif = bcx.tcx().const_qualif_map.borrow()[expr.id];
+    let adjusted_global = !qualif.intersects(check_const::NON_STATIC_BORROWS);
+    let global = if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) {
+        let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
+                                                      bcx.fcx.param_substs);
+
+        if qualif.intersects(check_const::HAS_STATIC_BORROWS) {
+            // Is borrowed as 'static, must return lvalue.
+
+            // Cast pointer to global, because constants have different types.
+            let const_ty = expr_ty_adjusted(bcx, expr);
+            let llty = type_of::type_of(bcx.ccx(), const_ty);
+            let global = PointerCast(bcx, global, llty.ptr_to());
+            let datum = Datum::new(global, const_ty, Lvalue);
+            return DatumBlock::new(bcx, datum.to_expr_datum());
+        }
+
+        // Otherwise, keep around and perform adjustments, if needed.
+        let const_ty = if adjusted_global {
+            expr_ty_adjusted(bcx, expr)
+        } else {
+            expr_ty(bcx, expr)
+        };
+
+        // This could use a better heuristic.
+        Some(if type_is_immediate(bcx.ccx(), const_ty) {
+            // Cast pointer to global, because constants have different types.
+            let llty = type_of::type_of(bcx.ccx(), const_ty);
+            let global = PointerCast(bcx, global, llty.ptr_to());
+            // Maybe just get the value directly, instead of loading it?
+            immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
+        } else {
+            let llty = type_of::type_of(bcx.ccx(), const_ty);
+            // HACK(eddyb) get around issues with lifetime intrinsics.
+            let scratch = alloca_no_lifetime(bcx, llty, "const");
+            let lldest = if !ty::type_is_structural(const_ty) {
+                // Cast pointer to slot, because constants have different types.
+                PointerCast(bcx, scratch, val_ty(global))
+            } else {
+                // In this case, memcpy_ty calls llvm.memcpy after casting both
+                // source and destination to i8*, so we don't need any casts.
+                scratch
+            };
+            memcpy_ty(bcx, lldest, global, const_ty);
+            Datum::new(scratch, const_ty, Rvalue::new(ByRef))
+        })
+    } else {
+        None
+    };
 
     let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                           expr.id,
                                                                           expr.span,
                                                                           false);
     fcx.push_ast_cleanup_scope(cleanup_debug_loc);
-    let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
-    let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
+    let datum = match global {
+        Some(rvalue) => rvalue.to_expr_datum(),
+        None => unpack_datum!(bcx, trans_unadjusted(bcx, expr))
+    };
+    let datum = if adjusted_global {
+        datum // trans::consts already performed adjustments.
+    } else {
+        unpack_datum!(bcx, apply_adjustments(bcx, expr, datum))
+    };
     bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
     return DatumBlock::new(bcx, datum);
 }
@@ -177,6 +278,54 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
     GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
 }
 
+// Retrieve the information we are losing (making dynamic) in an unsizing
+// adjustment.
+// When making a dtor, we need to do different things depending on the
+// ownership of the object.. mk_ty is a function for turning `unadjusted_ty`
+// into a type to be destructed. If we want to end up with a Box pointer,
+// then mk_ty should make a Box pointer (T -> Box<T>), if we want a
+// borrowed reference then it should be T -> &T.
+pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>,
+                                 kind: &ty::UnsizeKind<'tcx>,
+                                 id: ast::NodeId,
+                                 unadjusted_ty: Ty<'tcx>,
+                                 param_substs: &'tcx subst::Substs<'tcx>,
+                                 mk_ty: F) -> ValueRef where
+    F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
+{
+    // FIXME(#19596) workaround: `|t| t` causes monomorphization recursion
+    fn identity<T>(t: T) -> T { t }
+
+    debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})",
+           kind, id, unadjusted_ty.repr(ccx.tcx()));
+    match kind {
+        &ty::UnsizeLength(len) => C_uint(ccx, len),
+        &ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty {
+            ty::ty_struct(_, ref substs) => {
+                let ty_substs = substs.types.get_slice(subst::TypeSpace);
+                // The dtor for a field treats it like a value, so mk_ty
+                // should just be the identity function.
+                unsized_info(ccx, k, id, ty_substs[tp_index], param_substs, identity)
+            }
+            _ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
+                                         unadjusted_ty.repr(ccx.tcx()))[])
+        },
+        &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
+            // Note that we preserve binding levels here:
+            let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
+            let substs = ccx.tcx().mk_substs(substs);
+            let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
+                                                             substs: substs }));
+            let trait_ref = monomorphize::apply_param_substs(ccx.tcx(),
+                                                             param_substs,
+                                                             &trait_ref);
+            let box_ty = mk_ty(unadjusted_ty);
+            consts::ptrcast(meth::get_vtable(ccx, box_ty, trait_ref, param_substs),
+                            Type::vtable_ptr(ccx))
+        }
+    }
+}
+
 /// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted
 /// translation of `expr`.
 fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@@ -262,13 +411,17 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let datum = match autoref {
             &AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => {
                 debug!("  AutoPtr");
-                match a {
-                    &Some(box ref a) => {
-                        datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum));
-                    }
-                    &None => {}
+                if let &Some(box ref a) = a {
+                    datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum));
+                }
+                if !type_is_sized(bcx.tcx(), datum.ty) {
+                    // Arrange cleanup
+                    let lval = unpack_datum!(bcx,
+                        datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
+                    unpack_datum!(bcx, ref_fat_ptr(bcx, lval))
+                } else {
+                    unpack_datum!(bcx, auto_ref(bcx, datum, expr))
                 }
-                unpack_datum!(bcx, ref_ptr(bcx, expr, datum))
             }
             &ty::AutoUnsize(ref k) => {
                 debug!("  AutoUnsize");
@@ -288,139 +441,35 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         DatumBlock::new(bcx, datum)
     }
 
-    fn ref_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                           expr: &ast::Expr,
-                           datum: Datum<'tcx, Expr>)
-                           -> DatumBlock<'blk, 'tcx, Expr> {
-        debug!("ref_ptr(expr={}, datum={})",
-               expr.repr(bcx.tcx()),
-               datum.to_string(bcx.ccx()));
-
-        if !type_is_sized(bcx.tcx(), datum.ty) {
-            debug!("Taking address of unsized type {}",
-                   bcx.ty_to_string(datum.ty));
-            ref_fat_ptr(bcx, expr, datum)
-        } else {
-            debug!("Taking address of sized type {}",
-                   bcx.ty_to_string(datum.ty));
-            auto_ref(bcx, datum, expr)
-        }
-    }
-
-    // Retrieve the information we are losing (making dynamic) in an unsizing
-    // adjustment.
-    // When making a dtor, we need to do different things depending on the
-    // ownership of the object.. mk_ty is a function for turning `unadjusted_ty`
-    // into a type to be destructed. If we want to end up with a Box pointer,
-    // then mk_ty should make a Box pointer (T -> Box<T>), if we want a
-    // borrowed reference then it should be T -> &T.
-    fn unsized_info<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                   kind: &ty::UnsizeKind<'tcx>,
-                                   id: ast::NodeId,
-                                   unadjusted_ty: Ty<'tcx>,
-                                   mk_ty: F) -> ValueRef where
-        F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
-    {
-        // FIXME(#19596) workaround: `|t| t` causes monomorphization recursion
-        fn identity<T>(t: T) -> T { t }
-
-        debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})",
-               kind, id, unadjusted_ty.repr(bcx.tcx()));
-        match kind {
-            &ty::UnsizeLength(len) => C_uint(bcx.ccx(), len),
-            &ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty {
-                ty::ty_struct(_, ref substs) => {
-                    let ty_substs = substs.types.get_slice(subst::TypeSpace);
-                    // The dtor for a field treats it like a value, so mk_ty
-                    // should just be the identity function.
-                    unsized_info(bcx, k, id, ty_substs[tp_index], identity)
-                }
-                _ => bcx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
-                                          bcx.ty_to_string(unadjusted_ty))[])
-            },
-            &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
-                // Note that we preserve binding levels here:
-                let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
-                let substs = bcx.tcx().mk_substs(substs);
-                let trait_ref =
-                    ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
-                                                      substs: substs }));
-                let trait_ref = bcx.monomorphize(&trait_ref);
-                let box_ty = mk_ty(unadjusted_ty);
-                PointerCast(bcx,
-                            meth::get_vtable(bcx, box_ty, trait_ref),
-                            Type::vtable_ptr(bcx.ccx()))
-            }
-        }
-    }
-
     fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                expr: &ast::Expr,
                                datum: Datum<'tcx, Expr>,
                                k: &ty::UnsizeKind<'tcx>)
                                -> DatumBlock<'blk, 'tcx, Expr> {
+        let mut bcx = bcx;
         let tcx = bcx.tcx();
         let datum_ty = datum.ty;
         let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
         debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
         let dest_ty = ty::mk_open(tcx, unsized_ty);
         debug!("dest_ty={}", unsized_ty.repr(bcx.tcx()));
-        // Closures for extracting and manipulating the data and payload parts of
-        // the fat pointer.
-        let info = |bcx, _val| unsized_info(bcx,
-                                              k,
-                                              expr.id,
-                                              datum_ty,
-                                              |t| ty::mk_rptr(tcx,
-                                                              tcx.mk_region(ty::ReStatic),
-                                                              ty::mt{
-                                                                  ty: t,
-                                                                  mutbl: ast::MutImmutable
-                                                              }));
-        match *k {
-            ty::UnsizeStruct(..) =>
-                into_fat_ptr(bcx, expr, datum, dest_ty, |bcx, val| {
-                    PointerCast(bcx, val, type_of::type_of(bcx.ccx(), unsized_ty).ptr_to())
-                }, info),
-            ty::UnsizeLength(..) =>
-                into_fat_ptr(bcx, expr, datum, dest_ty, |bcx, val| {
-                    GEPi(bcx, val, &[0, 0])
-                }, info),
-            ty::UnsizeVtable(..) =>
-                into_fat_ptr(bcx, expr, datum, dest_ty, |_bcx, val| {
-                    PointerCast(bcx, val, Type::i8p(bcx.ccx()))
-                }, info),
-        }
-    }
 
-    fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               expr: &ast::Expr,
-                               datum: Datum<'tcx, Expr>)
-                               -> DatumBlock<'blk, 'tcx, Expr> {
-        let tcx = bcx.tcx();
-        let dest_ty = ty::close_type(tcx, datum.ty);
-        let base = |bcx, val| Load(bcx, get_dataptr(bcx, val));
-        let len = |bcx, val| Load(bcx, get_len(bcx, val));
-        into_fat_ptr(bcx, expr, datum, dest_ty, base, len)
-    }
-
-    fn into_fat_ptr<'blk, 'tcx, F, G>(bcx: Block<'blk, 'tcx>,
-                                      expr: &ast::Expr,
-                                      datum: Datum<'tcx, Expr>,
-                                      dest_ty: Ty<'tcx>,
-                                      base: F,
-                                      info: G)
-                                      -> DatumBlock<'blk, 'tcx, Expr> where
-        F: FnOnce(Block<'blk, 'tcx>, ValueRef) -> ValueRef,
-        G: FnOnce(Block<'blk, 'tcx>, ValueRef) -> ValueRef,
-    {
-        let mut bcx = bcx;
+        let info = unsized_info(bcx.ccx(), k, expr.id, datum_ty, bcx.fcx.param_substs,
+                                |t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t));
 
         // Arrange cleanup
         let lval = unpack_datum!(bcx,
                                  datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
-        let base = base(bcx, lval.val);
-        let info = info(bcx, lval.val);
+        // Compute the base pointer. This doesn't change the pointer value,
+        // but merely its type.
+        let base = match *k {
+            ty::UnsizeStruct(..) | ty::UnsizeVtable(..) => {
+                PointerCast(bcx, lval.val, type_of::type_of(bcx.ccx(), unsized_ty).ptr_to())
+            }
+            ty::UnsizeLength(..) => {
+                GEPi(bcx, lval.val, &[0u, 0u])
+            }
+        };
 
         let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
         Store(bcx, base, get_dataptr(bcx, scratch.val));
@@ -490,7 +539,8 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
         bcx = datum.store_to(bcx, base);
 
-        let info = unsized_info(bcx, k, expr.id, unboxed_ty, |t| ty::mk_uniq(tcx, t));
+        let info = unsized_info(bcx.ccx(), k, expr.id, unboxed_ty, bcx.fcx.param_substs,
+                                |t| ty::mk_uniq(tcx, t));
         Store(bcx, info, get_len(bcx, scratch.val));
 
         DatumBlock::new(bcx, scratch.to_expr_datum())
@@ -847,53 +897,25 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             //     pointer to that.
             let const_ty = expr_ty(bcx, ref_expr);
 
-            fn get_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: ast::DefId,
-                                   const_ty: Ty<'tcx>) -> ValueRef {
-                // For external constants, we don't inline.
-                if did.krate == ast::LOCAL_CRATE {
-                    // Case 1.
-
-                    // The LLVM global has the type of its initializer,
-                    // which may not be equal to the enum's type for
-                    // non-C-like enums.
-                    let val = base::get_item_val(bcx.ccx(), did.node);
-                    let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
-                    PointerCast(bcx, val, pty)
-                } else {
-                    // Case 2.
-                    base::get_extern_const(bcx.ccx(), did, const_ty)
-                }
-            }
-            let val = get_val(bcx, did, const_ty);
+            // For external constants, we don't inline.
+            let val = if did.krate == ast::LOCAL_CRATE {
+                // Case 1.
+
+                // The LLVM global has the type of its initializer,
+                // which may not be equal to the enum's type for
+                // non-C-like enums.
+                let val = base::get_item_val(bcx.ccx(), did.node);
+                let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
+                PointerCast(bcx, val, pty)
+            } else {
+                // Case 2.
+                base::get_extern_const(bcx.ccx(), did, const_ty)
+            };
             DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr))
         }
-        def::DefConst(did) => {
-            // First, inline any external constants into the local crate so we
-            // can be sure to get the LLVM value corresponding to it.
-            let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
-            if did.krate != ast::LOCAL_CRATE {
-                bcx.tcx().sess.span_bug(ref_expr.span,
-                                        "cross crate constant could not \
-                                         be inlined");
-            }
-            let val = base::get_item_val(bcx.ccx(), did.node);
-
-            // Next, we need to crate a ByRef rvalue datum to return. We can't
-            // use the normal .to_ref_datum() function because the type of
-            // `val` is not actually the same as `const_ty`.
-            //
-            // To get around this, we make a custom alloca slot with the
-            // appropriate type (const_ty), and then we cast it to a pointer of
-            // typeof(val), store the value, and then hand this slot over to
-            // the datum infrastructure.
-            let const_ty = expr_ty(bcx, ref_expr);
-            let llty = type_of::type_of(bcx.ccx(), const_ty);
-            let slot = alloca(bcx, llty, "const");
-            let pty = Type::from_ref(unsafe { llvm::LLVMTypeOf(val) }).ptr_to();
-            Store(bcx, val, PointerCast(bcx, slot, pty));
-
-            let datum = Datum::new(slot, const_ty, Rvalue::new(ByRef));
-            DatumBlock::new(bcx, datum.to_expr_datum())
+        def::DefConst(_) => {
+            bcx.sess().span_bug(ref_expr.span,
+                "constant expression should not reach expr::trans_def")
         }
         _ => {
             DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
@@ -1119,7 +1141,12 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             tvec::trans_fixed_vstore(bcx, expr, dest)
         }
         ast::ExprClosure(_, ref decl, ref body) => {
-            closure::trans_closure_expr(bcx, &**decl, &**body, expr.id, dest)
+            let dest = match dest {
+                SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
+                Ignore => closure::Dest::Ignore(bcx.ccx())
+            };
+            closure::trans_closure_expr(dest, &**decl, &**body, expr.id, bcx.fcx.param_substs)
+                .unwrap_or(bcx)
         }
         ast::ExprCall(ref f, ref args) => {
             if bcx.tcx().is_method_call(expr.id) {
@@ -1247,7 +1274,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                          ref_expr: &ast::Expr,
                                          def: def::Def,
-                                         param_substs: &subst::Substs<'tcx>)
+                                         param_substs: &'tcx subst::Substs<'tcx>)
                                          -> Datum<'tcx, Rvalue> {
     let _icx = push_ctxt("trans_def_datum_unadjusted");
 
@@ -1641,6 +1668,16 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
 }
 
+fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                           lval: Datum<'tcx, Lvalue>)
+                           -> DatumBlock<'blk, 'tcx, Expr> {
+    let dest_ty = ty::close_type(bcx.tcx(), lval.ty);
+    let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
+    memcpy_ty(bcx, scratch.val, lval.val, scratch.ty);
+
+    DatumBlock::new(bcx, scratch.to_expr_datum())
+}
+
 fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              expr: &ast::Expr,
                              subexpr: &ast::Expr)
@@ -1651,18 +1688,7 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     match sub_datum.ty.sty {
         ty::ty_open(_) => {
             // Opened DST value, close to a fat pointer
-            debug!("Closing fat pointer {}", bcx.ty_to_string(sub_datum.ty));
-
-            let scratch = rvalue_scratch_datum(bcx,
-                                               ty::close_type(bcx.tcx(), sub_datum.ty),
-                                               "fat_addr_of");
-            let base = Load(bcx, get_dataptr(bcx, sub_datum.val));
-            Store(bcx, base, get_dataptr(bcx, scratch.val));
-
-            let len = Load(bcx, get_len(bcx, sub_datum.val));
-            Store(bcx, len, get_len(bcx, scratch.val));
-
-            DatumBlock::new(bcx, scratch.to_expr_datum())
+            ref_fat_ptr(bcx, sub_datum)
         }
         _ => {
             // Sized value, ref to a thin pointer
@@ -1687,9 +1713,10 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let tcx = bcx.tcx();
     let is_simd = ty::type_is_simd(tcx, lhs_t);
-    let intype = {
-        if is_simd { ty::simd_type(tcx, lhs_t) }
-        else { lhs_t }
+    let intype = if is_simd {
+        ty::simd_type(tcx, lhs_t)
+    } else {
+        lhs_t
     };
     let is_float = ty::type_is_fp(intype);
     let is_signed = ty::type_is_signed(intype);
@@ -1766,24 +1793,10 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
       }
       ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
-        if ty::type_is_scalar(rhs_t) {
-            unpack_result!(bcx,
-                           base::compare_scalar_types(bcx,
-                                                      lhs,
-                                                      rhs,
-                                                      rhs_t,
-                                                      op.node,
-                                                      binop_debug_loc))
-        } else if is_simd {
-            base::compare_simd_types(bcx,
-                                     lhs,
-                                     rhs,
-                                     intype,
-                                     ty::simd_size(tcx, lhs_t),
-                                     op.node,
-                                     binop_debug_loc)
+        if is_simd {
+            base::compare_simd_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc)
         } else {
-            bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
+            base::compare_scalar_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc)
         }
       }
       _ => {
@@ -1997,7 +2010,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
     }
 }
 
-fn cast_is_noop<'tcx>(t_in: Ty<'tcx>, t_out: Ty<'tcx>) -> bool {
+pub fn cast_is_noop<'tcx>(t_in: Ty<'tcx>, t_out: Ty<'tcx>) -> bool {
     match (ty::deref(t_in, true), ty::deref(t_out, true)) {
         (Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
             t_in == t_out