From 9768ef5f9feaf7ea973e496d9df17211b76a3c2c Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Tue, 28 Feb 2017 17:50:28 +0200
Subject: [PATCH 01/14] rustc: add a TyLayout helper for type-related layout
 queries.

---
 src/librustc/ty/layout.rs                | 274 ++++++++++++++++++++++-
 src/librustc_trans/context.rs            |   4 +-
 src/librustc_trans/debuginfo/metadata.rs |   2 +-
 3 files changed, 267 insertions(+), 13 deletions(-)

diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 123db6e89476c..809091996b4e9 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -25,6 +25,7 @@ use std::cmp;
 use std::fmt;
 use std::i64;
 use std::iter;
+use std::ops::Deref;
 
 /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
 /// for a target, which contains everything needed to compute layouts.
@@ -904,7 +905,8 @@ pub enum Layout {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
         align: Align,
-        size: Size
+        element_size: Size,
+        count: u64
     },
 
     /// TyRawPtr or TyRef with a !Sized pointee.
@@ -1087,25 +1089,33 @@ impl<'a, 'gcx, 'tcx> Layout {
             // Arrays and slices.
             ty::TyArray(element, count) => {
                 let element = element.layout(infcx)?;
+                let element_size = element.size(dl);
+                let count = count as u64;
+                if element_size.checked_mul(count, dl).is_none() {
+                    return Err(LayoutError::SizeOverflow(ty));
+                }
                 Array {
                     sized: true,
                     align: element.align(dl),
-                    size: element.size(dl).checked_mul(count as u64, dl)
-                                 .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)?
+                    element_size: element_size,
+                    count: count
                 }
             }
             ty::TySlice(element) => {
+                let element = element.layout(infcx)?;
                 Array {
                     sized: false,
-                    align: element.layout(infcx)?.align(dl),
-                    size: Size::from_bytes(0)
+                    align: element.align(dl),
+                    element_size: element.size(dl),
+                    count: 0
                 }
             }
             ty::TyStr => {
                 Array {
                     sized: false,
                     align: dl.i8_align,
-                    size: Size::from_bytes(0)
+                    element_size: Size::from_bytes(1),
+                    count: 0
                 }
             }
 
@@ -1447,15 +1457,23 @@ impl<'a, 'gcx, 'tcx> Layout {
             }
 
             Vector { element, count } => {
-                let elem_size = element.size(dl);
-                let vec_size = match elem_size.checked_mul(count, dl) {
+                let element_size = element.size(dl);
+                let vec_size = match element_size.checked_mul(count, dl) {
                     Some(size) => size,
                     None => bug!("Layout::size({:?}): {} * {} overflowed",
-                                 self, elem_size.bytes(), count)
+                                 self, element_size.bytes(), count)
                 };
                 vec_size.abi_align(self.align(dl))
             }
 
+            Array { element_size, count, .. } => {
+                match element_size.checked_mul(count, dl) {
+                    Some(size) => size,
+                    None => bug!("Layout::size({:?}): {} * {} overflowed",
+                                 self, element_size.bytes(), count)
+                }
+            }
+
             FatPointer { metadata, .. } => {
                 // Effectively a (ptr, meta) tuple.
                 Pointer.size(dl).abi_align(metadata.align(dl))
@@ -1464,7 +1482,7 @@ impl<'a, 'gcx, 'tcx> Layout {
             }
 
             CEnum { discr, .. } => Int(discr).size(dl),
-            Array { size, .. } | General { size, .. } => size,
+            General { size, .. } => size,
             UntaggedUnion { ref variants } => variants.stride(),
 
             Univariant { ref variant, .. } |
@@ -1513,6 +1531,59 @@ impl<'a, 'gcx, 'tcx> Layout {
             }
         }
     }
+
+    pub fn field_offset(&self,
+                        dl: &TargetDataLayout,
+                        i: usize,
+                        variant_index: Option<usize>)
+                        -> Size {
+        match *self {
+            Scalar { .. } |
+            CEnum { .. } |
+            UntaggedUnion { .. } |
+            RawNullablePointer { .. } => {
+                Size::from_bytes(0)
+            }
+
+            Vector { element, count } => {
+                let element_size = element.size(dl);
+                let i = i as u64;
+                assert!(i < count);
+                Size::from_bytes(element_size.bytes() * count)
+            }
+
+            Array { element_size, count, .. } => {
+                let i = i as u64;
+                assert!(i < count);
+                Size::from_bytes(element_size.bytes() * count)
+            }
+
+            FatPointer { metadata, .. } => {
+                // Effectively a (ptr, meta) tuple.
+                assert!(i < 2);
+                if i == 0 {
+                    Size::from_bytes(0)
+                } else {
+                    Pointer.size(dl).abi_align(metadata.align(dl))
+                }
+            }
+
+            Univariant { ref variant, .. } => variant.offsets[i],
+
+            General { ref variants, .. } => {
+                let v = variant_index.expect("variant index required");
+                variants[v].offsets[i + 1]
+            }
+
+            StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
+                if Some(nndiscr as usize) == variant_index {
+                    nonnull.offsets[i]
+                } else {
+                    Size::from_bytes(0)
+                }
+            }
+        }
+    }
 }
 
 /// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1658,3 +1729,186 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
         }
     }
 }
+
+/// A pair of a type and its layout. Implements various
+/// type traversal APIs (e.g. recursing into fields).
+#[derive(Copy, Clone, Debug)]
+pub struct TyLayout<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub layout: &'tcx Layout,
+    pub variant_index: Option<usize>,
+}
+
+impl<'tcx> Deref for TyLayout<'tcx> {
+    type Target = Layout;
+    fn deref(&self) -> &Layout {
+        self.layout
+    }
+}
+
+impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
+    pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>)
+              -> Result<Self, LayoutError<'gcx>> {
+        let ty = normalize_associated_type(infcx, ty);
+
+        Ok(TyLayout {
+            ty: ty,
+            layout: ty.layout(infcx)?,
+            variant_index: None
+        })
+    }
+
+    pub fn for_variant(&self, variant_index: usize) -> Self {
+        TyLayout {
+            variant_index: Some(variant_index),
+            ..*self
+        }
+    }
+
+    pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size {
+        self.layout.field_offset(dl, i, self.variant_index)
+    }
+
+    pub fn field_count(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>) -> usize {
+        let ptr_field_count = || {
+            if let FatPointer { .. } = *self.layout {
+                2
+            } else {
+                bug!("TyLayout::field_count({:?}): not applicable", self)
+            }
+        };
+
+        match self.ty.sty {
+            ty::TyBool |
+            ty::TyChar |
+            ty::TyInt(_) |
+            ty::TyUint(_) |
+            ty::TyFloat(_) |
+            ty::TyFnPtr(_) |
+            ty::TyNever |
+            ty::TyFnDef(..) |
+            ty::TyDynamic(..) => {
+                bug!("TyLayout::field_type({:?}): not applicable", self)
+            }
+
+            // Potentially-fat pointers.
+            ty::TyRef(..) |
+            ty::TyRawPtr(_) => {
+                ptr_field_count()
+            }
+            ty::TyAdt(def, _) if def.is_box() => {
+                ptr_field_count()
+            }
+
+            // Arrays and slices.
+            ty::TyArray(_, count) => count,
+            ty::TySlice(_) |
+            ty::TyStr => 0,
+
+            // Tuples and closures.
+            ty::TyClosure(def_id, ref substs) => {
+                substs.upvar_tys(def_id, tcx).count()
+            }
+
+            ty::TyTuple(tys, _) => tys.len(),
+
+            // ADTs.
+            ty::TyAdt(def, _) => {
+                let v = if def.is_enum() {
+                    self.variant_index.expect("variant index required")
+                } else {
+                    assert_eq!(self.variant_index, None);
+                    0
+                };
+
+                def.variants[v].fields.len()
+            }
+
+            ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
+            ty::TyInfer(_) | ty::TyError => {
+                bug!("TyLayout::field_count: unexpected type `{}`", self.ty)
+            }
+        }
+    }
+
+    pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> {
+        let ptr_field_type = |pointee: Ty<'gcx>| {
+            let slice = |element: Ty<'gcx>| {
+                assert!(i < 2);
+                if i == 0 {
+                    tcx.mk_mut_ptr(element)
+                } else {
+                    tcx.types.usize
+                }
+            };
+            match tcx.struct_tail(pointee).sty {
+                ty::TySlice(element) => slice(element),
+                ty::TyStr => slice(tcx.types.u8),
+                ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()),
+                _ => bug!("TyLayout::field_type({:?}): not applicable", self)
+            }
+        };
+
+        match self.ty.sty {
+            ty::TyBool |
+            ty::TyChar |
+            ty::TyInt(_) |
+            ty::TyUint(_) |
+            ty::TyFloat(_) |
+            ty::TyFnPtr(_) |
+            ty::TyNever |
+            ty::TyFnDef(..) |
+            ty::TyDynamic(..) => {
+                bug!("TyLayout::field_type({:?}): not applicable", self)
+            }
+
+            // Potentially-fat pointers.
+            ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
+            ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                ptr_field_type(pointee)
+            }
+            ty::TyAdt(def, _) if def.is_box() => {
+                ptr_field_type(self.ty.boxed_ty())
+            }
+
+            // Arrays and slices.
+            ty::TyArray(element, _) |
+            ty::TySlice(element) => element,
+            ty::TyStr => tcx.types.u8,
+
+            // Tuples and closures.
+            ty::TyClosure(def_id, ref substs) => {
+                substs.upvar_tys(def_id, tcx).nth(i).unwrap()
+            }
+
+            ty::TyTuple(tys, _) => tys[i],
+
+            // SIMD vector types.
+            ty::TyAdt(def, ..) if def.repr.simd => {
+                self.ty.simd_type(tcx)
+            }
+
+            // ADTs.
+            ty::TyAdt(def, substs) => {
+                let v = if def.is_enum() {
+                    self.variant_index.expect("variant index required")
+                } else {
+                    assert_eq!(self.variant_index, None);
+                    0
+                };
+
+                def.variants[v].fields[i].ty(tcx, substs)
+            }
+
+            ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
+            ty::TyInfer(_) | ty::TyError => {
+                bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
+            }
+        }
+    }
+
+    pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize)
+                 -> Result<Self, LayoutError<'gcx>> {
+        TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i))
+    }
+}
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 1c1395f1b7762..beeafcb7e87fc 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -831,9 +831,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         TypeOfDepthLock(self.local())
     }
 
-    pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
+    pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> {
         self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
-            ty.layout(&infcx).unwrap_or_else(|e| {
+            ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| {
                 match e {
                     ty::layout::LayoutError::SizeOverflow(_) =>
                         self.sess().fatal(&e.to_string()),
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 049178a2575f3..93798e7bd3330 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1564,7 +1564,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         enum_llvm_type,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type: enum_type,
-            type_rep: type_rep,
+            type_rep: type_rep.layout,
             discriminant_type_metadata: discriminant_type_metadata,
             containing_scope: containing_scope,
             file_metadata: file_metadata,

From 03ce8869ca7e09c356ab6fbd808ce98bb3a501ad Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 2 Mar 2017 05:35:25 +0200
Subject: [PATCH 02/14] rustc_trans: avoid sizing_type_of everywhere possible.

---
 src/librustc_trans/abi.rs                | 12 +++---------
 src/librustc_trans/adt.rs                | 20 ++++++--------------
 src/librustc_trans/base.rs               | 10 ++++------
 src/librustc_trans/common.rs             |  6 ++----
 src/librustc_trans/consts.rs             |  2 +-
 src/librustc_trans/debuginfo/metadata.rs |  2 +-
 src/librustc_trans/debuginfo/mod.rs      |  2 +-
 src/librustc_trans/glue.rs               | 21 +++++++--------------
 src/librustc_trans/intrinsic.rs          | 14 +++++++-------
 src/librustc_trans/meth.rs               |  9 ++-------
 src/librustc_trans/mir/block.rs          |  4 ++--
 src/librustc_trans/mir/constant.rs       | 17 ++++++-----------
 src/librustc_trans/mir/rvalue.rs         |  2 +-
 src/librustc_trans/type_of.rs            | 14 ++++++++++----
 14 files changed, 53 insertions(+), 82 deletions(-)

diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 27a19d211c290..faf6dff6b2e48 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -439,14 +439,10 @@ impl FnType {
             match ret_ty.sty {
                 // These are not really pointers but pairs, (pointer, len)
                 ty::TyRef(_, ty::TypeAndMut { ty, .. }) => {
-                    let llty = type_of::sizing_type_of(ccx, ty);
-                    let llsz = llsize_of_alloc(ccx, llty);
-                    ret.attrs.set_dereferenceable(llsz);
+                    ret.attrs.set_dereferenceable(ccx.size_of(ty));
                 }
                 ty::TyAdt(def, _) if def.is_box() => {
-                    let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty());
-                    let llsz = llsize_of_alloc(ccx, llty);
-                    ret.attrs.set_dereferenceable(llsz);
+                    ret.attrs.set_dereferenceable(ccx.size_of(ret_ty.boxed_ty()));
                 }
                 _ => {}
             }
@@ -517,9 +513,7 @@ impl FnType {
                 args.push(info);
             } else {
                 if let Some(inner) = rust_ptr_attrs(ty, &mut arg) {
-                    let llty = type_of::sizing_type_of(ccx, inner);
-                    let llsz = llsize_of_alloc(ccx, llty);
-                    arg.attrs.set_dereferenceable(llsz);
+                    arg.attrs.set_dereferenceable(ccx.size_of(inner));
                 }
                 args.push(arg);
             }
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 058f37f62dd82..80ac40358088c 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -47,7 +47,7 @@ use std;
 
 use llvm::{ValueRef, True, IntEQ, IntNE};
 use rustc::ty::layout;
-use rustc::ty::{self, Ty, AdtKind};
+use rustc::ty::{self, Ty};
 use common::*;
 use builder::Builder;
 use base;
@@ -285,11 +285,6 @@ pub fn trans_get_discr<'a, 'tcx>(
     cast_to: Option<Type>,
     range_assert: bool
 ) -> ValueRef {
-    let (def, substs) = match t.sty {
-        ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs),
-        _ => bug!("{} is not an enum", t)
-    };
-
     debug!("trans_get_discr t: {:?}", t);
     let l = bcx.ccx.layout_of(t);
 
@@ -297,19 +292,17 @@ pub fn trans_get_discr<'a, 'tcx>(
         layout::CEnum { discr, min, max, .. } => {
             load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert)
         }
-        layout::General { discr, .. } => {
+        layout::General { discr, ref variants, .. } => {
             let ptr = bcx.struct_gep(scrutinee, 0);
             load_discr(bcx, discr, ptr, alignment,
-                       0, def.variants.len() as u64 - 1,
+                       0, variants.len() as u64 - 1,
                        range_assert)
         }
         layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0),
         layout::RawNullablePointer { nndiscr, .. } => {
             let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
-            let llptrty = type_of::sizing_type_of(bcx.ccx,
-                monomorphize::field_ty(bcx.tcx(), substs,
-                &def.variants[nndiscr as usize].fields[0]));
-            bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty))
+            let discr = bcx.load(scrutinee, alignment.to_align());
+            bcx.icmp(cmp, discr, C_null(val_ty(discr)))
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
             struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment)
@@ -383,9 +376,8 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
             assert_eq!(to, Disr(0));
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
             if to.0 != nndiscr {
-                let llptrty = type_of::sizing_type_of(bcx.ccx, nnty);
+                let llptrty = val_ty(val).element_type();
                 bcx.store(C_null(llptrty), val, None);
             }
         }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 6593b8e68d425..70b4d28eb9d84 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -59,7 +59,6 @@ use context::{SharedCrateContext, CrateContextList};
 use debuginfo;
 use declare;
 use machine;
-use machine::llsize_of;
 use meth;
 use mir;
 use monomorphize::{self, Instance};
@@ -534,14 +533,13 @@ pub fn memcpy_ty<'a, 'tcx>(
 ) {
     let ccx = bcx.ccx;
 
-    if type_is_zero_size(ccx, t) {
+    let size = ccx.size_of(t);
+    if size == 0 {
         return;
     }
 
-    let llty = type_of::type_of(ccx, t);
-    let llsz = llsize_of(ccx, llty);
-    let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t));
-    call_memcpy(bcx, dst, src, llsz, llalign as u32);
+    let align = align.unwrap_or_else(|| ccx.align_of(t));
+    call_memcpy(bcx, dst, src, C_uint(ccx, size), align);
 }
 
 pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index a0906bb02f5a3..cd96353636852 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -125,10 +125,8 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
 
 /// Identify types which have size zero at runtime.
 pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
-    use machine::llsize_of_alloc;
-    use type_of::sizing_type_of;
-    let llty = sizing_type_of(ccx, ty);
-    llsize_of_alloc(ccx, llty) == 0
+    let layout = ccx.layout_of(ty);
+    !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
 }
 
 /*
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 0c3d211912add..4177240e4a499 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -255,7 +255,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             ccx.statics_to_rauw().borrow_mut().push((g, new_g));
             new_g
         };
-        llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
+        llvm::LLVMSetAlignment(g, ccx.align_of(ty));
         llvm::LLVMSetInitializer(g, v);
 
         // As an optimization, all shared statics which do not have interior
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 93798e7bd3330..f1e1a3bb22136 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1772,7 +1772,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     let var_name = CString::new(var_name).unwrap();
     let linkage_name = CString::new(linkage_name).unwrap();
 
-    let global_align = type_of::align_of(cx, variable_type);
+    let global_align = cx.align_of(variable_type);
 
     unsafe {
         llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 8e86b50b3f7dd..1b7cf26853bc1 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -449,7 +449,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         LocalVariable    |
         CapturedVariable => (0, DW_TAG_auto_variable)
     };
-    let align = ::type_of::align_of(cx, variable_type);
+    let align = cx.align_of(variable_type);
 
     let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
     match (variable_access, &[][..]) {
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 41a9ab2842dcd..c2aa6c829415f 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -19,10 +19,8 @@ use llvm::{ValueRef};
 use rustc::traits;
 use rustc::ty::{self, Ty, TypeFoldable};
 use common::*;
-use machine::*;
 use meth;
 use monomorphize;
-use type_of::{sizing_type_of, align_of};
 use value::Value;
 use builder::Builder;
 
@@ -69,9 +67,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
     debug!("calculate size of DST: {}; with lost info: {:?}",
            t, Value(info));
     if bcx.ccx.shared().type_is_sized(t) {
-        let sizing_type = sizing_type_of(bcx.ccx, t);
-        let size = llsize_of_alloc(bcx.ccx, sizing_type);
-        let align = align_of(bcx.ccx, t);
+        let size = bcx.ccx.size_of(t);
+        let align = bcx.ccx.align_of(t);
         debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
                t, Value(info), size, align);
         let size = C_uint(bcx.ccx, size);
@@ -82,9 +79,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
         ty::TyAdt(def, substs) => {
             let ccx = bcx.ccx;
             // First get the size of all statically known fields.
-            // Don't use type_of::sizing_type_of because that expects t to be sized,
-            // and it also rounds up to alignment, which we want to avoid,
-            // as the unsized field's alignment could be smaller.
+            // Don't use size_of because it also rounds up to alignment, which we
+            // want to avoid, as the unsized field's alignment could be smaller.
             assert!(!t.is_simd());
             let layout = ccx.layout_of(t);
             debug!("DST {} layout: {:?}", t, layout);
@@ -154,14 +150,11 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             (meth::SIZE.get_usize(bcx, info), meth::ALIGN.get_usize(bcx, info))
         }
         ty::TySlice(_) | ty::TyStr => {
-            let unit_ty = t.sequence_element_type(bcx.tcx());
+            let unit = t.sequence_element_type(bcx.tcx());
             // The info in this case is the length of the str, so the size is that
             // times the unit size.
-            let llunit_ty = sizing_type_of(bcx.ccx, unit_ty);
-            let unit_align = llalign_of_min(bcx.ccx, llunit_ty);
-            let unit_size = llsize_of_alloc(bcx.ccx, llunit_ty);
-            (bcx.mul(info, C_uint(bcx.ccx, unit_size)),
-             C_uint(bcx.ccx, unit_align))
+            (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))),
+             C_uint(bcx.ccx, bcx.ccx.align_of(unit)))
         }
         _ => bug!("Unexpected unsized type, found {}", t)
     }
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 762bf8592ffcc..5e7d612d17f82 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -151,7 +151,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         }
         "min_align_of" => {
             let tp_ty = substs.type_at(0);
-            C_uint(ccx, type_of::align_of(ccx, tp_ty))
+            C_uint(ccx, ccx.align_of(tp_ty))
         }
         "min_align_of_val" => {
             let tp_ty = substs.type_at(0);
@@ -160,7 +160,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llalign
             } else {
-                C_uint(ccx, type_of::align_of(ccx, tp_ty))
+                C_uint(ccx, ccx.align_of(tp_ty))
             }
         }
         "pref_align_of" => {
@@ -234,7 +234,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             }
             let load = bcx.volatile_load(ptr);
             unsafe {
-                llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty));
+                llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty));
             }
             to_immediate(bcx, load, tp_ty)
         },
@@ -252,7 +252,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to());
                 let store = bcx.volatile_store(val, ptr);
                 unsafe {
-                    llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
+                    llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty));
                 }
             }
             C_nil(ccx)
@@ -634,7 +634,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
     if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
         if let Some(ty) = fn_ty.ret.cast {
             let ptr = bcx.pointercast(llresult, ty.ptr_to());
-            bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty)));
+            bcx.store(llval, ptr, Some(ccx.align_of(ret_ty)));
         } else {
             store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty);
         }
@@ -651,7 +651,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                             -> ValueRef {
     let ccx = bcx.ccx;
     let lltp_ty = type_of::type_of(ccx, tp_ty);
-    let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
+    let align = C_i32(ccx, ccx.align_of(tp_ty) as i32);
     let size = machine::llsize_of(ccx, lltp_ty);
     let int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
 
@@ -685,7 +685,7 @@ fn memset_intrinsic<'a, 'tcx>(
     count: ValueRef
 ) -> ValueRef {
     let ccx = bcx.ccx;
-    let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
+    let align = C_i32(ccx, ccx.align_of(ty) as i32);
     let lltp_ty = type_of::type_of(ccx, ty);
     let size = machine::llsize_of(ccx, lltp_ty);
     let dst = bcx.pointercast(dst, Type::i8p(ccx));
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 75ab407614050..f5f924178589a 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -17,7 +17,6 @@ use consts;
 use machine;
 use monomorphize;
 use type_::Type;
-use type_of::*;
 use value::Value;
 use rustc::ty;
 
@@ -80,14 +79,10 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // Not in the cache. Build it.
     let nullptr = C_null(Type::nil(ccx).ptr_to());
 
-    let size_ty = sizing_type_of(ccx, ty);
-    let size = machine::llsize_of_alloc(ccx, size_ty);
-    let align = align_of(ccx, ty);
-
     let mut components: Vec<_> = [
         callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)),
-        C_uint(ccx, size),
-        C_uint(ccx, align)
+        C_uint(ccx, ccx.size_of(ty)),
+        C_uint(ccx, ccx.align_of(ty))
     ].iter().cloned().collect();
 
     if let Some(trait_ref) = trait_ref {
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 226d40948c4dc..3b2823364b6b2 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -24,8 +24,8 @@ use consts;
 use machine::llalign_of_min;
 use meth;
 use monomorphize;
+use type_of;
 use tvec;
-use type_of::{self, align_of};
 use type_::Type;
 
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -910,7 +910,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
         let in_type = val.ty;
         let out_type = dst.ty.to_ty(bcx.tcx());;
-        let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type));
+        let llalign = cmp::min(bcx.ccx.align_of(in_type), bcx.ccx.align_of(out_type));
         self.store_operand(bcx, cast_ptr, Some(llalign), val);
     }
 
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 107b0982af982..cd26e312586a6 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -145,7 +145,7 @@ impl<'tcx> Const<'tcx> {
         } else {
             // Otherwise, or if the value is not immediate, we create
             // a constant LLVM global and cast its address if necessary.
-            let align = type_of::align_of(ccx, self.ty);
+            let align = ccx.align_of(self.ty);
             let ptr = consts::addr_of(ccx, self.llval, align, "const");
             OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned)
         };
@@ -721,7 +721,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     Base::Value(llval) => {
                         // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
                         let align = if self.ccx.shared().type_is_sized(ty) {
-                            type_of::align_of(self.ccx, ty)
+                            self.ccx.align_of(ty)
                         } else {
                             self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
                         };
@@ -1033,25 +1033,20 @@ fn trans_const<'a, 'tcx>(
             C_vector(vals)
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
             if variant_index as u64 == nndiscr {
                 assert_eq!(vals.len(), 1);
                 vals[0]
             } else {
-                C_null(type_of::sizing_type_of(ccx, nnty))
+                C_null(type_of::type_of(ccx, t))
             }
         }
         layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
             if variant_index as u64 == nndiscr {
                 C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
             } else {
-                let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
-                let vals = fields.iter().map(|&ty| {
-                    // Always use null even if it's not the `discrfield`th
-                    // field; see #8506.
-                    C_null(type_of::sizing_type_of(ccx, ty))
-                }).collect::<Vec<ValueRef>>();
-                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
+                // Always use null even if it's not the `discrfield`th
+                // field; see #8506.
+                C_null(type_of::type_of(ccx, t))
             }
         }
         _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index d487aa6cd5be6..12633720ef87f 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -438,7 +438,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
                 let llty = type_of::type_of(bcx.ccx, content_ty);
                 let llsize = machine::llsize_of(bcx.ccx, llty);
-                let align = type_of::align_of(bcx.ccx, content_ty);
+                let align = bcx.ccx.align_of(content_ty);
                 let llalign = C_uint(bcx.ccx, align);
                 let llty_ptr = llty.ptr_to();
                 let box_ty = bcx.tcx().mk_box(content_ty);
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index a5722e6e520d0..b195429711d15 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -322,10 +322,16 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
     llty
 }
 
-pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
-                          -> machine::llalign {
-    let layout = cx.layout_of(t);
-    layout.align(&cx.tcx().data_layout).abi() as machine::llalign
+impl<'a, 'tcx> CrateContext<'a, 'tcx> {
+    pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
+        let layout = self.layout_of(ty);
+        layout.align(&self.tcx().data_layout).abi() as machine::llalign
+    }
+
+    pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
+        let layout = self.layout_of(ty);
+        layout.size(&self.tcx().data_layout).bytes() as machine::llsize
+    }
 }
 
 fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {

From b957df00166201803ba3a6bbe3846d872baca98d Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Fri, 10 Mar 2017 06:25:51 +0200
Subject: [PATCH 03/14] rustc: add some abstractions to ty::layout for a more
 concise API.

---
 src/librustc/middle/intrinsicck.rs       |   2 +-
 src/librustc/ty/layout.rs                | 144 +++++++++++++++++------
 src/librustc_lint/types.rs               |   2 +-
 src/librustc_trans/abi.rs                |   2 +-
 src/librustc_trans/adt.rs                |   5 +-
 src/librustc_trans/base.rs               |  12 +-
 src/librustc_trans/common.rs             |   6 +-
 src/librustc_trans/context.rs            |  61 ++++++++--
 src/librustc_trans/debuginfo/metadata.rs |   5 +-
 src/librustc_trans/glue.rs               |   3 +-
 src/librustc_trans/mir/block.rs          |   3 +-
 src/librustc_trans/mir/constant.rs       |   6 +-
 src/librustc_trans/mir/lvalue.rs         |   3 +-
 src/librustc_trans/mir/mod.rs            |   3 +-
 src/librustc_trans/mir/operand.rs        |   2 +-
 src/librustc_trans/mir/rvalue.rs         |   2 +-
 src/librustc_trans/type_of.rs            |  11 +-
 17 files changed, 191 insertions(+), 81 deletions(-)

diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index c9722adc9510c..8dc298b9c2a17 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
             let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
             match (&from.sty, sk_to) {
                 (&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
-                        if size_to == Pointer.size(&self.infcx.tcx.data_layout) => {
+                        if size_to == Pointer.size(self.infcx) => {
                     struct_span_err!(self.infcx.tcx.sess, span, E0591,
                                      "`{}` is zero-sized and can't be transmuted to `{}`",
                                      from, to)
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 809091996b4e9..b48a152ef096c 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -202,6 +202,16 @@ impl TargetDataLayout {
     }
 }
 
+pub trait HasDataLayout: Copy {
+    fn data_layout(&self) -> &TargetDataLayout;
+}
+
+impl<'a> HasDataLayout for &'a TargetDataLayout {
+    fn data_layout(&self) -> &TargetDataLayout {
+        self
+    }
+}
+
 /// Endianness of the target, which must match cfg(target-endian).
 #[derive(Copy, Clone)]
 pub enum Endian {
@@ -242,7 +252,9 @@ impl Size {
         Size::from_bytes((self.bytes() + mask) & !mask)
     }
 
-    pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {
+    pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> {
+        let dl = cx.data_layout();
+
         // Each Size is less than dl.obj_size_bound(), so the sum is
         // also less than 1 << 62 (and therefore can't overflow).
         let bytes = self.bytes() + offset.bytes();
@@ -254,7 +266,9 @@ impl Size {
         }
     }
 
-    pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option<Size> {
+    pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> {
+        let dl = cx.data_layout();
+
         // Each Size is less than dl.obj_size_bound(), so the sum is
         // also less than 1 << 62 (and therefore can't overflow).
         match self.bytes().checked_mul(count) {
@@ -354,7 +368,9 @@ impl Integer {
         }
     }
 
-    pub fn align(&self, dl: &TargetDataLayout)-> Align {
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        let dl = cx.data_layout();
+
         match *self {
             I1 => dl.i1_align,
             I8 => dl.i8_align,
@@ -408,7 +424,9 @@ impl Integer {
     }
 
     /// Find the smallest integer with the given alignment.
-    pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option<Integer> {
+    pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> {
+        let dl = cx.data_layout();
+
         let wanted = align.abi();
         for &candidate in &[I8, I16, I32, I64] {
             let ty = Int(candidate);
@@ -420,7 +438,9 @@ impl Integer {
     }
 
     /// Get the Integer type from an attr::IntType.
-    pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer {
+    pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
+        let dl = cx.data_layout();
+
         match ity {
             attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
             attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
@@ -450,7 +470,7 @@ impl Integer {
         let min_default = I8;
 
         if let Some(ity) = repr.int {
-            let discr = Integer::from_attr(&tcx.data_layout, ity);
+            let discr = Integer::from_attr(tcx, ity);
             let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
             if discr < fit {
                 bug!("Integer::repr_discr: `#[repr]` hint too small for \
@@ -491,7 +511,9 @@ pub enum Primitive {
 }
 
 impl Primitive {
-    pub fn size(self, dl: &TargetDataLayout) -> Size {
+    pub fn size<C: HasDataLayout>(self, cx: C) -> Size {
+        let dl = cx.data_layout();
+
         match self {
             Int(I1) | Int(I8) => Size::from_bits(8),
             Int(I16) => Size::from_bits(16),
@@ -502,7 +524,9 @@ impl Primitive {
         }
     }
 
-    pub fn align(self, dl: &TargetDataLayout) -> Align {
+    pub fn align<C: HasDataLayout>(self, cx: C) -> Align {
+        let dl = cx.data_layout();
+
         match self {
             Int(I1) => dl.i1_align,
             Int(I8) => dl.i8_align,
@@ -682,8 +706,8 @@ impl<'a, 'gcx, 'tcx> Struct {
     }
 
     /// Determine whether a structure would be zero-sized, given its fields.
-    pub fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-                                  -> Result<bool, LayoutError<'gcx>>
+    fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
+                              -> Result<bool, LayoutError<'gcx>>
     where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
         for field in fields {
             let field = field?;
@@ -831,7 +855,7 @@ pub struct Union {
 }
 
 impl<'a, 'gcx, 'tcx> Union {
-    pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
+    fn new(dl: &TargetDataLayout, packed: bool) -> Union {
         Union {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
             min_size: Size::from_bytes(0),
@@ -840,10 +864,10 @@ impl<'a, 'gcx, 'tcx> Union {
     }
 
     /// Extend the Struct with more fields.
-    pub fn extend<I>(&mut self, dl: &TargetDataLayout,
-                     fields: I,
-                     scapegoat: Ty<'gcx>)
-                     -> Result<(), LayoutError<'gcx>>
+    fn extend<I>(&mut self, dl: &TargetDataLayout,
+                 fields: I,
+                 scapegoat: Ty<'gcx>)
+                 -> Result<(), LayoutError<'gcx>>
     where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
         for (index, field) in fields.enumerate() {
             let field = field?;
@@ -1450,7 +1474,9 @@ impl<'a, 'gcx, 'tcx> Layout {
         }
     }
 
-    pub fn size(&self, dl: &TargetDataLayout) -> Size {
+    pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
+        let dl = cx.data_layout();
+
         match *self {
             Scalar { value, .. } | RawNullablePointer { value, .. } => {
                 value.size(dl)
@@ -1492,7 +1518,9 @@ impl<'a, 'gcx, 'tcx> Layout {
         }
     }
 
-    pub fn align(&self, dl: &TargetDataLayout) -> Align {
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        let dl = cx.data_layout();
+
         match *self {
             Scalar { value, .. } | RawNullablePointer { value, .. } => {
                 value.align(dl)
@@ -1532,11 +1560,13 @@ impl<'a, 'gcx, 'tcx> Layout {
         }
     }
 
-    pub fn field_offset(&self,
-                        dl: &TargetDataLayout,
-                        i: usize,
-                        variant_index: Option<usize>)
-                        -> Size {
+    pub fn field_offset<C: HasDataLayout>(&self,
+                                          cx: C,
+                                          i: usize,
+                                          variant_index: Option<usize>)
+                                          -> Size {
+        let dl = cx.data_layout();
+
         match *self {
             Scalar { .. } |
             CEnum { .. } |
@@ -1615,7 +1645,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
         // First try computing a static layout.
         let err = match ty.layout(infcx) {
             Ok(layout) => {
-                return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout)));
+                return Ok(SizeSkeleton::Known(layout.size(tcx)));
             }
             Err(err) => err
         };
@@ -1746,18 +1776,55 @@ impl<'tcx> Deref for TyLayout<'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
-    pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>)
-              -> Result<Self, LayoutError<'gcx>> {
-        let ty = normalize_associated_type(infcx, ty);
+pub trait HasTyCtxt<'tcx>: HasDataLayout {
+    fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
+}
+
+impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.data_layout
+    }
+}
+
+impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
+        self.global_tcx()
+    }
+}
+
+impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
+        self.tcx.global_tcx()
+    }
+}
+
+pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
+    type TyLayout;
+
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
+}
+
+impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
+    type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
+
+    fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
+        let ty = normalize_associated_type(self, ty);
 
         Ok(TyLayout {
             ty: ty,
-            layout: ty.layout(infcx)?,
+            layout: ty.layout(self)?,
             variant_index: None
         })
     }
+}
 
+impl<'a, 'tcx> TyLayout<'tcx> {
     pub fn for_variant(&self, variant_index: usize) -> Self {
         TyLayout {
             variant_index: Some(variant_index),
@@ -1765,11 +1832,13 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
         }
     }
 
-    pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size {
-        self.layout.field_offset(dl, i, self.variant_index)
+    pub fn field_offset<C: HasDataLayout>(&self, cx: C, i: usize) -> Size {
+        self.layout.field_offset(cx, i, self.variant_index)
     }
 
-    pub fn field_count(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>) -> usize {
+    pub fn field_count<C: HasTyCtxt<'tcx>>(&self, cx: C) -> usize {
+        let tcx = cx.tcx();
+
         let ptr_field_count = || {
             if let FatPointer { .. } = *self.layout {
                 2
@@ -1831,9 +1900,11 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
         }
     }
 
-    pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> {
-        let ptr_field_type = |pointee: Ty<'gcx>| {
-            let slice = |element: Ty<'gcx>| {
+    pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
+        let tcx = cx.tcx();
+
+        let ptr_field_type = |pointee: Ty<'tcx>| {
+            let slice = |element: Ty<'tcx>| {
                 assert!(i < 2);
                 if i == 0 {
                     tcx.mk_mut_ptr(element)
@@ -1907,8 +1978,7 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
         }
     }
 
-    pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize)
-                 -> Result<Self, LayoutError<'gcx>> {
-        TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i))
+    pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
+        cx.layout_of(self.field_type(cx, i))
     }
 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 529afe0215e53..2318bb81affe6 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -733,7 +733,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
                 });
 
                 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
-                    let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
+                    let discr_size = Primitive::Int(discr).size(cx.tcx).bytes();
 
                     debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
                       t, size.bytes(), layout);
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index faf6dff6b2e48..425fafaabd8d2 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -35,13 +35,13 @@ use type_of;
 
 use rustc::hir;
 use rustc::ty::{self, Ty};
+use rustc::ty::layout::{Layout, LayoutTyper};
 
 use libc::c_uint;
 use std::cmp;
 
 pub use syntax::abi::Abi;
 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
-use rustc::ty::layout::Layout;
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 enum ArgKind {
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 80ac40358088c..129231010b0d1 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -46,8 +46,8 @@ use super::Disr;
 use std;
 
 use llvm::{ValueRef, True, IntEQ, IntNE};
-use rustc::ty::layout;
 use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, LayoutTyper};
 use common::*;
 use builder::Builder;
 use base;
@@ -246,9 +246,8 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
     assert_eq!(size%align, 0);
     assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align);
     let align_units = size/align;
-    let dl = &cx.tcx().data_layout;
     let layout_align = layout::Align::from_bytes(align, align).unwrap();
-    if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) {
+    if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) {
         Type::array(&Type::from_integer(cx, ity), align_units)
     } else {
         Type::array(&Type::vector(&Type::i32(cx), align/4),
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 70b4d28eb9d84..d54c3174bdb1e 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1263,8 +1263,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         // (delay format until we actually need it)
         let record = |kind, opt_discr_size, variants| {
             let type_desc = format!("{:?}", ty);
-            let overall_size = layout.size(&tcx.data_layout);
-            let align = layout.align(&tcx.data_layout);
+            let overall_size = layout.size(tcx);
+            let align = layout.align(tcx);
             tcx.sess.code_stats.borrow_mut().record_type_size(kind,
                                                               type_desc,
                                                               align,
@@ -1300,8 +1300,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
                     session::FieldInfo {
                         name: field_name.to_string(),
                         offset: offset.bytes(),
-                        size: field_layout.size(&tcx.data_layout).bytes(),
-                        align: field_layout.align(&tcx.data_layout).abi(),
+                        size: field_layout.size(tcx).bytes(),
+                        align: field_layout.align(tcx).abi(),
                     }
                 }
             }
@@ -1311,8 +1311,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
             session::VariantInfo {
                 name: Some(name.to_string()),
                 kind: session::SizeKind::Exact,
-                align: value.align(&tcx.data_layout).abi(),
-                size: value.size(&tcx.data_layout).bytes(),
+                align: value.align(tcx).abi(),
+                size: value.size(tcx).bytes(),
                 fields: vec![],
             }
         };
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index cd96353636852..5d58c93538922 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -27,7 +27,7 @@ use monomorphize;
 use type_::Type;
 use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::hir;
 
@@ -63,7 +63,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
         Layout::UntaggedUnion { .. } |
         Layout::RawNullablePointer { .. } |
         Layout::StructWrappedNullablePointer { .. } => {
-            !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
+            !layout.is_unsized() && layout.size(ccx).bytes() == 0
         }
     }
 }
@@ -126,7 +126,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
 /// Identify types which have size zero at runtime.
 pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
     let layout = ccx.layout_of(ty);
-    !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
+    !layout.is_unsized() && layout.size(ccx).bytes() == 0
 }
 
 /*
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index beeafcb7e87fc..d9c3ba2a2b646 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -29,6 +29,7 @@ use type_::Type;
 use rustc_data_structures::base_n;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{LayoutTyper, TyLayout};
 use session::config::NoDebugInfo;
 use session::Session;
 use session::config;
@@ -831,18 +832,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         TypeOfDepthLock(self.local())
     }
 
-    pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> {
-        self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
-            ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| {
-                match e {
-                    ty::layout::LayoutError::SizeOverflow(_) =>
-                        self.sess().fatal(&e.to_string()),
-                    _ => bug!("failed to get layout for `{}`: {}", ty, e)
-                }
-            })
-        })
-    }
-
     pub fn check_overflow(&self) -> bool {
         self.shared.check_overflow
     }
@@ -954,6 +943,54 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> {
+    fn data_layout(&self) -> &ty::layout::TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.tcx
+    }
+}
+
+impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> {
+    fn data_layout(&self) -> &ty::layout::TargetDataLayout {
+        &self.shared.tcx.data_layout
+    }
+}
+
+impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.shared.tcx
+    }
+}
+
+impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
+    type TyLayout = TyLayout<'tcx>;
+
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
+            infcx.layout_of(ty).unwrap_or_else(|e| {
+                match e {
+                    ty::layout::LayoutError::SizeOverflow(_) =>
+                        self.sess().fatal(&e.to_string()),
+                    _ => bug!("failed to get layout for `{}`: {}", ty, e)
+                }
+            })
+        })
+    }
+}
+
+impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
+    type TyLayout = TyLayout<'tcx>;
+
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        self.shared.layout_of(ty)
+    }
+}
+
 pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
 
 impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> {
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index f1e1a3bb22136..ccb693aa41f4c 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -35,7 +35,8 @@ use rustc_data_structures::ToHex;
 use {type_of, machine, monomorphize};
 use common::{self, CrateContext};
 use type_::Type;
-use rustc::ty::{self, AdtKind, Ty, layout};
+use rustc::ty::{self, AdtKind, Ty};
+use rustc::ty::layout::{self, LayoutTyper};
 use session::config;
 use util::nodemap::FxHashMap;
 use util::common::path2cstr;
@@ -900,7 +901,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
         let offsets = match *layout {
             layout::Univariant { ref variant, .. } => &variant.offsets,
             layout::Vector { element, count } => {
-                let element_size = element.size(&cx.tcx().data_layout).bytes();
+                let element_size = element.size(cx).bytes();
                 tmp = (0..count).
                   map(|i| layout::Size::from_bytes(i*element_size))
                   .collect::<Vec<layout::Size>>();
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index c2aa6c829415f..59876a7f2a201 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -18,6 +18,7 @@ use llvm;
 use llvm::{ValueRef};
 use rustc::traits;
 use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::LayoutTyper;
 use common::*;
 use meth;
 use monomorphize;
@@ -47,7 +48,7 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>
             if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
                 scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
                     let layout = t.layout(&infcx).unwrap();
-                    if layout.size(&scx.tcx().data_layout).bytes() == 0 {
+                    if layout.size(scx).bytes() == 0 {
                         // `Box<ZeroSizeType>` does not allocate.
                         false
                     } else {
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 3b2823364b6b2..49ab01723231c 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -12,7 +12,8 @@ use llvm::{self, ValueRef, BasicBlockRef};
 use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
 use rustc::middle::const_val::ConstInt;
-use rustc::ty::{self, layout, TypeFoldable};
+use rustc::ty::{self, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
 use base::{self, Lifetime};
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index cd26e312586a6..a612cc1f79d29 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -18,7 +18,8 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
-use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -990,7 +991,6 @@ fn trans_const<'a, 'tcx>(
     vals: &[ValueRef]
 ) -> ValueRef {
     let l = ccx.layout_of(t);
-    let dl = &ccx.tcx().data_layout;
     let variant_index = match *kind {
         mir::AggregateKind::Adt(_, index, _, _) => index,
         _ => 0,
@@ -1013,7 +1013,7 @@ fn trans_const<'a, 'tcx>(
             let mut vals_with_discr = vec![lldiscr];
             vals_with_discr.extend_from_slice(vals);
             let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
-            let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
+            let needed_padding = l.size(ccx).bytes() - variant.stride().bytes();
             if needed_padding > 0 {
                 contents.push(padding(ccx, needed_padding));
             }
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index dd8c1d0e1f031..fc889604ab88e 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::ty::{self, layout, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 6419f41f86b6d..8b5bdb6a31a1e 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -11,7 +11,8 @@
 use libc::c_uint;
 use llvm::{self, ValueRef, BasicBlockRef};
 use llvm::debuginfo::DIScope;
-use rustc::ty::{self, layout};
+use rustc::ty;
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir::{self, Mir};
 use rustc::mir::tcx::LvalueTy;
 use rustc::ty::subst::Substs;
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index da24c03fdc2a0..771a88238b2b7 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -10,7 +10,7 @@
 
 use llvm::ValueRef;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 12633720ef87f..8f7cb914c4735 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef};
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index b195429711d15..c459191561dd6 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -13,6 +13,7 @@ use adt;
 use common::*;
 use machine;
 use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::LayoutTyper;
 use trans_item::DefPathBasedNames;
 use type_::Type;
 
@@ -117,14 +118,14 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
         return llsizingty;
     }
 
-    let r = layout.size(&cx.tcx().data_layout).bytes();
+    let r = layout.size(cx).bytes();
     let l = machine::llsize_of_alloc(cx, llsizingty);
     if r != l {
         bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
              r, l, t, layout);
     }
 
-    let r = layout.align(&cx.tcx().data_layout).abi();
+    let r = layout.align(cx).abi();
     let l = machine::llalign_of_min(cx, llsizingty) as u64;
     if r != l {
         bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
@@ -324,13 +325,11 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
 impl<'a, 'tcx> CrateContext<'a, 'tcx> {
     pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
-        let layout = self.layout_of(ty);
-        layout.align(&self.tcx().data_layout).abi() as machine::llalign
+        self.layout_of(ty).align(self).abi() as machine::llalign
     }
 
     pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
-        let layout = self.layout_of(ty);
-        layout.size(&self.tcx().data_layout).bytes() as machine::llsize
+        self.layout_of(ty).size(self).bytes() as machine::llsize
     }
 }
 

From 6ac00de41f9d99c5ee87ef6a84876fb55cabdf31 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Fri, 10 Mar 2017 06:25:57 +0200
Subject: [PATCH 04/14] rustc_trans: use ty::layout for ABI computation instead
 of LLVM types.

---
 src/librustc/ty/layout.rs              |  32 +-
 src/librustc_trans/abi.rs              | 572 +++++++++++++++++--------
 src/librustc_trans/adt.rs              |  24 +-
 src/librustc_trans/cabi_aarch64.rs     | 178 +++-----
 src/librustc_trans/cabi_arm.rs         | 155 ++-----
 src/librustc_trans/cabi_asmjs.rs       |  37 +-
 src/librustc_trans/cabi_mips.rs        |  88 +---
 src/librustc_trans/cabi_mips64.rs      |  88 +---
 src/librustc_trans/cabi_msp430.rs      |  21 +-
 src/librustc_trans/cabi_nvptx.rs       |  21 +-
 src/librustc_trans/cabi_nvptx64.rs     |  21 +-
 src/librustc_trans/cabi_powerpc.rs     |  93 +---
 src/librustc_trans/cabi_powerpc64.rs   | 180 +++-----
 src/librustc_trans/cabi_s390x.rs       | 140 ++----
 src/librustc_trans/cabi_sparc.rs       |  90 +---
 src/librustc_trans/cabi_sparc64.rs     | 181 +++-----
 src/librustc_trans/cabi_x86.rs         |  37 +-
 src/librustc_trans/cabi_x86_64.rs      | 518 +++++++++-------------
 src/librustc_trans/cabi_x86_win64.rs   |  45 +-
 src/librustc_trans/mir/block.rs        |  28 +-
 src/librustc_trans/mir/mod.rs          |  19 +-
 src/librustc_trans/type_of.rs          | 119 +----
 src/test/codegen/function-arguments.rs |   4 +-
 23 files changed, 1001 insertions(+), 1690 deletions(-)

diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index b48a152ef096c..3ecd126d318b3 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1853,13 +1853,15 @@ impl<'a, 'tcx> TyLayout<'tcx> {
             ty::TyInt(_) |
             ty::TyUint(_) |
             ty::TyFloat(_) |
-            ty::TyFnPtr(_) |
-            ty::TyNever |
-            ty::TyFnDef(..) |
-            ty::TyDynamic(..) => {
+            ty::TyFnPtr(_) => {
                 bug!("TyLayout::field_type({:?}): not applicable", self)
             }
 
+            // ZSTs.
+            ty::TyNever |
+            ty::TyFnDef(..) |
+            ty::TyDynamic(..) => 0,
+
             // Potentially-fat pointers.
             ty::TyRef(..) |
             ty::TyRawPtr(_) => {
@@ -1883,14 +1885,13 @@ impl<'a, 'tcx> TyLayout<'tcx> {
 
             // ADTs.
             ty::TyAdt(def, _) => {
-                let v = if def.is_enum() {
-                    self.variant_index.expect("variant index required")
-                } else {
-                    assert_eq!(self.variant_index, None);
+                let v = self.variant_index.unwrap_or(0);
+                if def.variants.is_empty() {
+                    assert_eq!(v, 0);
                     0
-                };
-
-                def.variants[v].fields.len()
+                } else {
+                    def.variants[v].fields.len()
+                }
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
@@ -1961,14 +1962,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
 
             // ADTs.
             ty::TyAdt(def, substs) => {
-                let v = if def.is_enum() {
-                    self.variant_index.expect("variant index required")
-                } else {
-                    assert_eq!(self.variant_index, None);
-                    0
-                };
-
-                def.variants[v].fields[i].ty(tcx, substs)
+                def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs)
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 425fafaabd8d2..8cf51d5cf819d 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
+use llvm::{self, ValueRef, AttributePlace};
 use base;
 use builder::Builder;
 use common::{type_is_fat_ptr, C_uint};
@@ -29,16 +29,17 @@ use cabi_sparc;
 use cabi_sparc64;
 use cabi_nvptx;
 use cabi_nvptx64;
-use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
+use machine::llalign_of_min;
 use type_::Type;
 use type_of;
 
 use rustc::hir;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{Layout, LayoutTyper};
+use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size};
 
 use libc::c_uint;
 use std::cmp;
+use std::iter;
 
 pub use syntax::abi::Abi;
 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
@@ -133,32 +134,279 @@ impl ArgAttributes {
     }
 }
 
+pub trait CastTarget {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type;
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum RegKind {
+    Integer,
+    Float,
+    Vector
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Reg {
+    pub kind: RegKind,
+    pub size: Size,
+}
+
+macro_rules! reg_ctor {
+    ($name:ident, $kind:ident, $bits:expr) => {
+        pub fn $name() -> Reg {
+            Reg {
+                kind: RegKind::$kind,
+                size: Size::from_bits($bits)
+            }
+        }
+    }
+}
+
+impl Reg {
+    reg_ctor!(i8, Integer, 8);
+    reg_ctor!(i16, Integer, 16);
+    reg_ctor!(i32, Integer, 32);
+    reg_ctor!(i64, Integer, 64);
+
+    reg_ctor!(f32, Float, 32);
+    reg_ctor!(f64, Float, 64);
+}
+
+impl CastTarget for Reg {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type {
+        match self.kind {
+            RegKind::Integer => Type::ix(ccx, self.size.bits()),
+            RegKind::Float => {
+                match self.size.bits() {
+                    32 => Type::f32(ccx),
+                    64 => Type::f64(ccx),
+                    _ => bug!("unsupported float: {:?}", self)
+                }
+            }
+            RegKind::Vector => {
+                // Try to pick an integer at least twice as small.
+                let bits = self.size.bits();
+                let unit_bits = if bits <= 16 {
+                    8
+                } else if bits <= 32 {
+                    16
+                } else if bits <= 64 {
+                    32
+                } else {
+                    64
+                };
+                let count = bits / unit_bits;
+                assert_eq!(bits, unit_bits * count);
+                Type::vector(&Type::ix(ccx, unit_bits), count)
+            }
+        }
+    }
+}
+
+impl CastTarget for (Reg, Reg) {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type {
+        Type::struct_(ccx, &[
+            self.0.llvm_type(ccx),
+            self.1.llvm_type(ccx)
+        ], false)
+    }
+}
+
+/// An argument passed entirely registers with the
+/// same kind (e.g. HFA / HVA on PPC64 and AArch64).
+#[derive(Copy, Clone)]
+pub struct Uniform {
+    pub unit: Reg,
+
+    /// The total size of the argument, which can be:
+    /// * equal to `unit.size` (one scalar/vector)
+    /// * a multiple of `unit.size` (an array of scalar/vectors)
+    /// * if `unit.kind` is `Integer`, the last element
+    ///   can be shorter, i.e. `{ i64, i64, i32 }` for
+    ///   64-bit integers with a total size of 20 bytes
+    pub total: Size,
+}
+
+impl CastTarget for Uniform {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type {
+        let llunit = self.unit.llvm_type(ccx);
+
+        if self.total <= self.unit.size {
+            return llunit;
+        }
+
+        let count = self.total.bytes() / self.unit.size.bytes();
+        let rem_bytes = self.total.bytes() % self.unit.size.bytes();
+
+        if rem_bytes == 0 {
+            return Type::array(&llunit, count);
+        }
+
+        // Only integers can be really split further.
+        assert_eq!(self.unit.kind, RegKind::Integer);
+
+        let args: Vec<_> = (0..count).map(|_| llunit)
+            .chain(iter::once(Type::ix(ccx, rem_bytes * 8)))
+            .collect();
+
+        Type::struct_(ccx, &args, false)
+    }
+}
+
+pub trait LayoutExt<'tcx> {
+    fn is_aggregate(&self) -> bool;
+    fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg>;
+}
+
+impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
+    fn is_aggregate(&self) -> bool {
+        match *self.layout {
+            Layout::Scalar { .. } |
+            Layout::RawNullablePointer { .. } |
+            Layout::CEnum { .. } |
+            Layout::Vector { .. } => false,
+
+            Layout::Array { .. } |
+            Layout::FatPointer { .. } |
+            Layout::Univariant { .. } |
+            Layout::UntaggedUnion { .. } |
+            Layout::General { .. } |
+            Layout::StructWrappedNullablePointer { .. } => true
+        }
+    }
+
+    fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
+        match *self.layout {
+            // The primitives for this algorithm.
+            Layout::Scalar { value, .. } |
+            Layout::RawNullablePointer { value, .. } => {
+                let kind = match value {
+                    layout::Int(_) |
+                    layout::Pointer => RegKind::Integer,
+                    layout::F32 |
+                    layout::F64 => RegKind::Float
+                };
+                Some(Reg {
+                    kind,
+                    size: self.size(ccx)
+                })
+            }
+
+            Layout::CEnum { .. } => {
+                Some(Reg {
+                    kind: RegKind::Integer,
+                    size: self.size(ccx)
+                })
+            }
+
+            Layout::Vector { .. } => {
+                Some(Reg {
+                    kind: RegKind::Integer,
+                    size: self.size(ccx)
+                })
+            }
+
+            Layout::Array { count, .. } => {
+                if count > 0 {
+                    self.field(ccx, 0).homogenous_aggregate(ccx)
+                } else {
+                    None
+                }
+            }
+
+            Layout::Univariant { ref variant, .. } => {
+                let mut unaligned_offset = Size::from_bytes(0);
+                let mut result = None;
+
+                for i in 0..self.field_count(ccx) {
+                    if unaligned_offset != variant.offsets[i] {
+                        return None;
+                    }
+
+                    let field = self.field(ccx, i);
+                    match (result, field.homogenous_aggregate(ccx)) {
+                        // The field itself must be a homogenous aggregate.
+                        (_, None) => return None,
+                        // If this is the first field, record the unit.
+                        (None, Some(unit)) => {
+                            result = Some(unit);
+                        }
+                        // For all following fields, the unit must be the same.
+                        (Some(prev_unit), Some(unit)) => {
+                            if prev_unit != unit {
+                                return None;
+                            }
+                        }
+                    }
+
+                    // Keep track of the offset (without padding).
+                    let size = field.size(ccx);
+                    match unaligned_offset.checked_add(size, ccx) {
+                        Some(offset) => unaligned_offset = offset,
+                        None => return None
+                    }
+                }
+
+                // There needs to be no padding.
+                if unaligned_offset != self.size(ccx) {
+                    None
+                } else {
+                    result
+                }
+            }
+
+            Layout::UntaggedUnion { .. } => {
+                let mut max = Size::from_bytes(0);
+                let mut result = None;
+
+                for i in 0..self.field_count(ccx) {
+                    let field = self.field(ccx, i);
+                    match (result, field.homogenous_aggregate(ccx)) {
+                        // The field itself must be a homogenous aggregate.
+                        (_, None) => return None,
+                        // If this is the first field, record the unit.
+                        (None, Some(unit)) => {
+                            result = Some(unit);
+                        }
+                        // For all following fields, the unit must be the same.
+                        (Some(prev_unit), Some(unit)) => {
+                            if prev_unit != unit {
+                                return None;
+                            }
+                        }
+                    }
+
+                    // Keep track of the offset (without padding).
+                    let size = field.size(ccx);
+                    if size > max {
+                        max = size;
+                    }
+                }
+
+                // There needs to be no padding.
+                if max != self.size(ccx) {
+                    None
+                } else {
+                    result
+                }
+            }
+
+            // Rust-specific types, which we can ignore for C ABIs.
+            Layout::FatPointer { .. } |
+            Layout::General { .. } |
+            Layout::StructWrappedNullablePointer { .. } => None
+        }
+    }
+}
+
 /// Information about how a specific C type
 /// should be passed to or returned from a function
 ///
 /// This is borrowed from clang's ABIInfo.h
 #[derive(Clone, Copy, Debug)]
-pub struct ArgType {
+pub struct ArgType<'tcx> {
     kind: ArgKind,
-    /// Original LLVM type
-    pub original_ty: Type,
-    /// Sizing LLVM type (pointers are opaque).
-    /// Unlike original_ty, this is guaranteed to be complete.
-    ///
-    /// For example, while we're computing the function pointer type in
-    /// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`.
-    /// The field type will likely end up being `void(%Foo)*`, but we cannot
-    /// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`,
-    /// until `%Foo` is completed by having all of its field types inserted,
-    /// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers
-    /// with opaque ones, resulting in `{i8*}` for `Foo`.
-    /// ABI-specific logic can then look at the size, alignment and fields of
-    /// `{i8*}` in order to determine how the argument will be passed.
-    /// Only later will `original_ty` aka `%Foo` be used in the LLVM function
-    /// pointer type, without ever having introspected it.
-    pub ty: Type,
-    /// Signedness for integer types, None for other types
-    pub signedness: Option<bool>,
+    pub layout: TyLayout<'tcx>,
     /// Coerced LLVM Type
     pub cast: Option<Type>,
     /// Dummy argument, which is emitted before the real argument
@@ -167,26 +415,24 @@ pub struct ArgType {
     pub attrs: ArgAttributes
 }
 
-impl ArgType {
-    fn new(original_ty: Type, ty: Type) -> ArgType {
+impl<'a, 'tcx> ArgType<'tcx> {
+    fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> {
         ArgType {
             kind: ArgKind::Direct,
-            original_ty: original_ty,
-            ty: ty,
-            signedness: None,
+            layout: layout,
             cast: None,
             pad: None,
             attrs: ArgAttributes::default()
         }
     }
 
-    pub fn make_indirect(&mut self, ccx: &CrateContext) {
+    pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) {
         assert_eq!(self.kind, ArgKind::Direct);
 
         // Wipe old attributes, likely not valid through indirection.
         self.attrs = ArgAttributes::default();
 
-        let llarg_sz = llsize_of_alloc(ccx, self.ty);
+        let llarg_sz = self.layout.size(ccx).bytes();
 
         // For non-immediate arguments the callee gets its own copy of
         // the value on the stack, so there are no aliases. It's also
@@ -205,17 +451,44 @@ impl ArgType {
 
     pub fn extend_integer_width_to(&mut self, bits: u64) {
         // Only integers have signedness
-        if let Some(signed) = self.signedness {
-            if self.ty.int_width() < bits {
-                self.attrs.set(if signed {
-                    ArgAttribute::SExt
-                } else {
-                    ArgAttribute::ZExt
-                });
+        let (i, signed) = match *self.layout {
+            Layout::Scalar { value, .. } => {
+                match value {
+                    layout::Int(i) => {
+                        if self.layout.ty.is_integral() {
+                            (i, self.layout.ty.is_signed())
+                        } else {
+                            return;
+                        }
+                    }
+                    _ => return
+                }
             }
+
+            // Rust enum types that map onto C enums also need to follow
+            // the target ABI zero-/sign-extension rules.
+            Layout::CEnum { discr, signed, .. } => (discr, signed),
+
+            _ => return
+        };
+
+        if i.size().bits() < bits {
+            self.attrs.set(if signed {
+                ArgAttribute::SExt
+            } else {
+                ArgAttribute::ZExt
+            });
         }
     }
 
+    pub fn cast_to<T: CastTarget>(&mut self, ccx: &CrateContext, target: T) {
+        self.cast = Some(target.llvm_type(ccx));
+    }
+
+    pub fn pad_with(&mut self, ccx: &CrateContext, reg: Reg) {
+        self.pad = Some(reg.llvm_type(ccx));
+    }
+
     pub fn is_indirect(&self) -> bool {
         self.kind == ArgKind::Indirect
     }
@@ -224,18 +497,24 @@ impl ArgType {
         self.kind == ArgKind::Ignore
     }
 
+    /// Get the LLVM type for an lvalue of the original Rust type of
+    /// this argument/return, i.e. the result of `type_of::type_of`.
+    pub fn memory_ty(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
+        type_of::type_of(ccx, self.layout.ty)
+    }
+
     /// Store a direct/indirect value described by this ArgType into a
     /// lvalue for the original Rust type of this argument/return.
     /// Can be used for both storing formal arguments into Rust variables
     /// or results of call/invoke instructions into their destinations.
-    pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) {
+    pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) {
         if self.is_ignore() {
             return;
         }
         let ccx = bcx.ccx;
         if self.is_indirect() {
-            let llsz = llsize_of(ccx, self.ty);
-            let llalign = llalign_of_min(ccx, self.ty);
+            let llsz = C_uint(ccx, self.layout.size(ccx).bytes());
+            let llalign = self.layout.align(ccx).abi();
             base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
         } else if let Some(ty) = self.cast {
             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
@@ -243,8 +522,8 @@ impl ArgType {
             let can_store_through_cast_ptr = false;
             if can_store_through_cast_ptr {
                 let cast_dst = bcx.pointercast(dst, ty.ptr_to());
-                let llalign = llalign_of_min(ccx, self.ty);
-                bcx.store(val, cast_dst, Some(llalign));
+                let llalign = self.layout.align(ccx).abi();
+                bcx.store(val, cast_dst, Some(llalign as u32));
             } else {
                 // The actual return type is a struct, but the ABI
                 // adaptation code has cast it into some scalar type.  The
@@ -271,21 +550,21 @@ impl ArgType {
                 base::call_memcpy(bcx,
                                   bcx.pointercast(dst, Type::i8p(ccx)),
                                   bcx.pointercast(llscratch, Type::i8p(ccx)),
-                                  C_uint(ccx, llsize_of_alloc(ccx, self.ty)),
-                                  cmp::min(llalign_of_min(ccx, self.ty),
-                                           llalign_of_min(ccx, ty)) as u32);
+                                  C_uint(ccx, self.layout.size(ccx).bytes()),
+                                  cmp::min(self.layout.align(ccx).abi() as u32,
+                                           llalign_of_min(ccx, ty)));
 
                 base::Lifetime::End.call(bcx, llscratch);
             }
         } else {
-            if self.original_ty == Type::i1(ccx) {
+            if self.layout.ty == ccx.tcx().types.bool {
                 val = bcx.zext(val, Type::i8(ccx));
             }
             bcx.store(val, dst, None);
         }
     }
 
-    pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) {
+    pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: ValueRef) {
         if self.pad.is_some() {
             *idx += 1;
         }
@@ -304,30 +583,30 @@ impl ArgType {
 /// I will do my best to describe this structure, but these
 /// comments are reverse-engineered and may be inaccurate. -NDM
 #[derive(Clone, Debug)]
-pub struct FnType {
+pub struct FnType<'tcx> {
     /// The LLVM types of each argument.
-    pub args: Vec<ArgType>,
+    pub args: Vec<ArgType<'tcx>>,
 
     /// LLVM return type.
-    pub ret: ArgType,
+    pub ret: ArgType<'tcx>,
 
     pub variadic: bool,
 
     pub cconv: llvm::CallConv
 }
 
-impl FnType {
-    pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                         sig: ty::FnSig<'tcx>,
-                         extra_args: &[Ty<'tcx>]) -> FnType {
+impl<'a, 'tcx> FnType<'tcx> {
+    pub fn new(ccx: &CrateContext<'a, 'tcx>,
+               sig: ty::FnSig<'tcx>,
+               extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
         let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
         fn_ty.adjust_for_abi(ccx, sig);
         fn_ty
     }
 
-    pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                sig: ty::FnSig<'tcx>,
-                                extra_args: &[Ty<'tcx>]) -> FnType {
+    pub fn new_vtable(ccx: &CrateContext<'a, 'tcx>,
+                      sig: ty::FnSig<'tcx>,
+                      extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
         let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
         // Don't pass the vtable, it's not an argument of the virtual fn.
         fn_ty.args[1].ignore();
@@ -335,9 +614,9 @@ impl FnType {
         fn_ty
     }
 
-    fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            sig: ty::FnSig<'tcx>,
-                            extra_args: &[Ty<'tcx>]) -> FnType {
+    pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>,
+                      sig: ty::FnSig<'tcx>,
+                      extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
         use self::Abi::*;
         let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
             RustIntrinsic | PlatformIntrinsic |
@@ -394,23 +673,11 @@ impl FnType {
         };
 
         let arg_of = |ty: Ty<'tcx>, is_return: bool| {
+            let mut arg = ArgType::new(ccx.layout_of(ty));
             if ty.is_bool() {
-                let llty = Type::i1(ccx);
-                let mut arg = ArgType::new(llty, llty);
                 arg.attrs.set(ArgAttribute::ZExt);
-                arg
             } else {
-                let mut arg = ArgType::new(type_of::type_of(ccx, ty),
-                                           type_of::sizing_type_of(ccx, ty));
-                if ty.is_integral() {
-                    arg.signedness = Some(ty.is_signed());
-                }
-                // Rust enum types that map onto C enums also need to follow
-                // the target ABI zero-/sign-extension rules.
-                if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) {
-                    arg.signedness = Some(signed);
-                }
-                if llsize_of_alloc(ccx, arg.ty) == 0 {
+                if arg.layout.size(ccx).bytes() == 0 {
                     // For some forsaken reason, x86_64-pc-windows-gnu
                     // doesn't ignore zero-sized struct arguments.
                     // The same is true for s390x-unknown-linux-gnu.
@@ -419,8 +686,8 @@ impl FnType {
                         arg.ignore();
                     }
                 }
-                arg
             }
+            arg
         };
 
         let ret_ty = sig.output();
@@ -491,13 +758,9 @@ impl FnType {
         for ty in inputs.iter().chain(extra_args.iter()) {
             let mut arg = arg_of(ty, false);
 
-            if type_is_fat_ptr(ccx, ty) {
-                let original_tys = arg.original_ty.field_types();
-                let sizing_tys = arg.ty.field_types();
-                assert_eq!((original_tys.len(), sizing_tys.len()), (2, 2));
-
-                let mut data = ArgType::new(original_tys[0], sizing_tys[0]);
-                let mut info = ArgType::new(original_tys[1], sizing_tys[1]);
+            if let ty::layout::FatPointer { .. } = *arg.layout {
+                let mut data = ArgType::new(arg.layout.field(ccx, 0));
+                let mut info = ArgType::new(arg.layout.field(ccx, 1));
 
                 if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
                     data.attrs.set(ArgAttribute::NonNull);
@@ -527,43 +790,51 @@ impl FnType {
         }
     }
 
-    fn adjust_for_abi<'a, 'tcx>(&mut self,
-                                ccx: &CrateContext<'a, 'tcx>,
-                                sig: ty::FnSig<'tcx>) {
+    fn adjust_for_abi(&mut self,
+                      ccx: &CrateContext<'a, 'tcx>,
+                      sig: ty::FnSig<'tcx>) {
         let abi = sig.abi;
         if abi == Abi::Unadjusted { return }
 
         if abi == Abi::Rust || abi == Abi::RustCall ||
            abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            let fixup = |arg: &mut ArgType| {
-                let mut llty = arg.ty;
-
-                // Replace newtypes with their inner-most type.
-                while llty.kind() == llvm::TypeKind::Struct {
-                    let inner = llty.field_types();
-                    if inner.len() != 1 {
-                        break;
-                    }
-                    llty = inner[0];
+            let fixup = |arg: &mut ArgType<'tcx>| {
+                if !arg.layout.is_aggregate() {
+                    return;
                 }
 
-                if !llty.is_aggregate() {
-                    // Scalars and vectors, always immediate.
-                    if llty != arg.ty {
+                let size = arg.layout.size(ccx);
+
+                if let Some(unit) = arg.layout.homogenous_aggregate(ccx) {
+                    // Replace newtypes with their inner-most type.
+                    if unit.size == size {
                         // Needs a cast as we've unpacked a newtype.
-                        arg.cast = Some(llty);
+                        arg.cast_to(ccx, unit);
+                        return;
+                    }
+
+                    // Pairs of floats.
+                    if unit.kind == RegKind::Float {
+                        if unit.size.checked_mul(2, ccx) == Some(size) {
+                            arg.cast_to(ccx, Uniform {
+                                unit,
+                                total: size
+                            });
+                            return;
+                        }
                     }
-                    return;
                 }
 
-                let size = llsize_of_alloc(ccx, llty);
-                if size > llsize_of_alloc(ccx, ccx.int_type()) {
+                if size > layout::Pointer.size(ccx) {
                     arg.make_indirect(ccx);
-                } else if size > 0 {
+                } else {
                     // We want to pass small aggregates as immediates, but using
                     // a LLVM aggregate type for this leads to bad optimizations,
                     // so we pick an appropriately sized integer type instead.
-                    arg.cast = Some(Type::ix(ccx, size * 8));
+                    arg.cast_to(ccx, Reg {
+                        kind: RegKind::Integer,
+                        size
+                    });
                 }
             };
             // Fat pointers are returned by-value.
@@ -599,14 +870,7 @@ impl FnType {
                 cabi_x86_64::compute_abi_info(ccx, self);
             },
             "aarch64" => cabi_aarch64::compute_abi_info(ccx, self),
-            "arm" => {
-                let flavor = if ccx.sess().target.target.target_os == "ios" {
-                    cabi_arm::Flavor::Ios
-                } else {
-                    cabi_arm::Flavor::General
-                };
-                cabi_arm::compute_abi_info(ccx, self, flavor);
-            },
+            "arm" => cabi_arm::compute_abi_info(ccx, self),
             "mips" => cabi_mips::compute_abi_info(ccx, self),
             "mips64" => cabi_mips64::compute_abi_info(ccx, self),
             "powerpc" => cabi_powerpc::compute_abi_info(ccx, self),
@@ -627,16 +891,18 @@ impl FnType {
         }
     }
 
-    pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
+    pub fn llvm_type(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
         let mut llargument_tys = Vec::new();
 
         let llreturn_ty = if self.ret.is_ignore() {
             Type::void(ccx)
         } else if self.ret.is_indirect() {
-            llargument_tys.push(self.ret.original_ty.ptr_to());
+            llargument_tys.push(self.ret.memory_ty(ccx).ptr_to());
             Type::void(ccx)
         } else {
-            self.ret.cast.unwrap_or(self.ret.original_ty)
+            self.ret.cast.unwrap_or_else(|| {
+                type_of::immediate_type_of(ccx, self.ret.layout.ty)
+            })
         };
 
         for arg in &self.args {
@@ -649,9 +915,11 @@ impl FnType {
             }
 
             let llarg_ty = if arg.is_indirect() {
-                arg.original_ty.ptr_to()
+                arg.memory_ty(ccx).ptr_to()
             } else {
-                arg.cast.unwrap_or(arg.original_ty)
+                arg.cast.unwrap_or_else(|| {
+                    type_of::immediate_type_of(ccx, arg.layout.ty)
+                })
             };
 
             llargument_tys.push(llarg_ty);
@@ -699,72 +967,6 @@ impl FnType {
     }
 }
 
-pub fn align_up_to(off: usize, a: usize) -> usize {
-    return (off + a - 1) / a * a;
-}
-
-fn align(off: usize, ty: Type, pointer: usize) -> usize {
-    let a = ty_align(ty, pointer);
-    return align_up_to(off, a);
-}
-
-pub fn ty_align(ty: Type, pointer: usize) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => pointer,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ty_align(elt, pointer)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ty_align(elt, pointer) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
-}
-
-pub fn ty_size(ty: Type, pointer: usize) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => pointer,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter().fold(0, |s, t| {
-                    align(s, *t, pointer) + ty_size(*t, pointer)
-                });
-                align(size, ty, pointer)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, pointer);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, pointer);
-            len * eltsz
-        },
-        _ => bug!("ty_size: unhandled type")
-    }
+pub fn align_up_to(off: u64, a: u64) -> u64 {
+    (off + a - 1) / a * a
 }
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 129231010b0d1..4f86082758246 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -95,15 +95,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
     generic_type_of(cx, t, None, false, false)
 }
 
-
-// Pass dst=true if the type you are passing is a DST. Yes, we could figure
-// this out, but if you call this on an unsized type without realising it, you
-// are going to get the wrong type (it will not include the unsized parts of it).
-pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                t: Ty<'tcx>, dst: bool) -> Type {
-    generic_type_of(cx, t, None, true, dst)
-}
-
 pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     t: Ty<'tcx>, name: &str) -> Type {
     generic_type_of(cx, t, Some(name), false, false)
@@ -149,7 +140,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             };
             let nnty = monomorphize::field_ty(cx.tcx(), substs,
                 &def.variants[nndiscr as usize].fields[0]);
-            type_of::sizing_type_of(cx, nnty)
+            if let layout::Scalar { value: layout::Pointer, .. } = *cx.layout_of(nnty) {
+                Type::i8p(cx)
+            } else {
+                type_of::type_of(cx, nnty)
+            }
         }
         layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
             let fields = compute_fields(cx, t, nndiscr as usize, false);
@@ -181,10 +176,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        layout::Vector { element, count } => {
-            let elem_ty = Type::from_primitive(cx, element);
-            Type::vector(&elem_ty, count)
-        }
         layout::UntaggedUnion { ref variants, .. }=> {
             // Use alignment-sized ints to fill all the union storage.
             let size = variants.stride().bytes();
@@ -258,11 +249,10 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
 
 fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
                              variant: &layout::Struct,
-                             sizing: bool, dst: bool) -> Vec<Type> {
+                             sizing: bool, _dst: bool) -> Vec<Type> {
     let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
     if sizing {
-        fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty))
-            .map(|ty| type_of::sizing_type_of(cx, ty)).collect()
+        bug!()
     } else {
         fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
     }
diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_trans/cabi_aarch64.rs
index 59a84439950ba..c8c5af714d92a 100644
--- a/src/librustc_trans/cabi_aarch64.rs
+++ b/src/librustc_trans/cabi_aarch64.rs
@@ -8,163 +8,99 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 8)
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
-    fn check_array(ty: Type) -> Option<(Type, u64)> {
-        let len = ty.array_length() as u64;
-        if len == 0 {
-            return None
-        }
-        let elt = ty.element_type();
-
-        // if our element is an HFA/HVA, so are we; multiply members by our len
-        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
-    }
-
-    fn check_struct(ty: Type) -> Option<(Type, u64)> {
-        let str_tys = ty.field_types();
-        if str_tys.len() == 0 {
-            return None
-        }
-
-        let mut prev_base_ty = None;
-        let mut members = 0;
-        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
-            match (prev_base_ty, opt_homog_agg) {
-                // field isn't itself an HFA, so we aren't either
-                (_, None) => return None,
-
-                // first field - store its type and number of members
-                (None, Some((field_ty, field_members))) => {
-                    prev_base_ty = Some(field_ty);
-                    members = field_members;
-                },
 
-                // 2nd or later field - give up if it's a different type; otherwise incr. members
-                (Some(prev_ty), Some((field_ty, field_members))) => {
-                    if prev_ty != field_ty {
-                        return None;
-                    }
-                    members += field_members;
-                }
-            }
-        }
-
-        // Because of previous checks, we know prev_base_ty is Some(...) because
-        //   1. str_tys has at least one element; and
-        //   2. prev_base_ty was filled in (or we would've returned early)
-        let (base_ty, members) = (prev_base_ty.unwrap(), members);
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+                                     -> Option<Uniform> {
+    arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+        let size = arg.layout.size(ccx);
 
-        // Ensure there is no padding.
-        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
-            Some((base_ty, members))
-        } else {
-            None
+        // Ensure we have at most four uniquely addressable members.
+        if size > unit.size.checked_mul(4, ccx).unwrap() {
+            return None;
         }
-    }
 
-    let homog_agg = match ty.kind() {
-        Float  => Some((ty, 1)),
-        Double => Some((ty, 1)),
-        Array  => check_array(ty),
-        Struct => check_struct(ty),
-        Vector => match ty_size(ty) {
-            4|8 => Some((ty, 1)),
-            _   => None
-        },
-        _ => None
-    };
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 64 || size.bits() == 128
+        };
 
-    // Ensure we have at most four uniquely addressable members
-    homog_agg.and_then(|(base_ty, members)| {
-        if members > 0 && members <= 4 {
-            Some((base_ty, members))
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
         } else {
             None
         }
     })
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
         return;
     }
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
-        ret.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+        ret.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(ret.ty);
-    if size <= 16 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        ret.cast = Some(llty);
+
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
     ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(32);
         return;
     }
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
-        arg.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+        arg.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(arg.ty);
-    if size <= 16 {
-        let llty = if size == 0 {
-            Type::array(&Type::i64(ccx), 0)
-        } else if size == 1 {
-            Type::i8(ccx)
-        } else if size == 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = arg.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        arg.cast = Some(llty);
+
+        arg.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
     arg.make_indirect(ccx);
 }
 
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    }
-}
-
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs
index 85b26074bae6d..7a91cad511d6d 100644
--- a/src/librustc_trans/cabi_arm.rs
+++ b/src/librustc_trans/cabi_arm.rs
@@ -8,156 +8,53 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{self, align_up_to, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
 
-use std::cmp;
-
-pub enum Flavor {
-    General,
-    Ios
-}
-
-type TyAlignFn = fn(ty: Type) -> usize;
-
-fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize {
-    let a = align_fn(ty);
-    return align_up_to(off, a);
-}
-
-fn general_ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 4)
-}
-
-// For more information see:
-// ARMv7
-// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual
-//    /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html
-// ARMv6
-// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual
-//    /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html
-fn ios_ty_align(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8),
-        Pointer => 4,
-        Float => 4,
-        Double => 4,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ios_ty_align(elt)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ios_ty_align(elt) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
-}
-
-fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter()
-                                  .fold(0, |s, t| {
-                                      align(s, *t, align_fn) + ty_size(*t, align_fn)
-                                  });
-                align(size, ty, align_fn)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, align_fn);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, align_fn);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
         return;
     }
-    let size = ty_size(ret.ty, align_fn);
-    if size <= 4 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 32 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
         } else {
-            Type::i32(ccx)
+            Reg::i32()
         };
-        ret.cast = Some(llty);
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
     ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(32);
         return;
     }
-    let align = align_fn(arg.ty);
-    let size = ty_size(arg.ty, align_fn);
-    let llty = if align <= 4 {
-        Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64)
-    } else {
-        Type::array(&Type::i64(ccx), ((size + 7) / 8) as u64)
-    };
-    arg.cast = Some(llty);
+    let align = arg.layout.align(ccx).abi();
+    let total = arg.layout.size(ccx);
+    arg.cast_to(ccx, Uniform {
+        unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
+        total
+    });
 }
 
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    }
-}
-
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
-    let align_fn = match flavor {
-        Flavor::General => general_ty_align as TyAlignFn,
-        Flavor::Ios => ios_ty_align as TyAlignFn,
-    };
-
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
-        classify_ret_ty(ccx, &mut fty.ret, align_fn);
+        classify_ret_ty(ccx, &mut fty.ret);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        classify_arg_ty(ccx, arg, align_fn);
+        classify_arg_ty(ccx, arg);
     }
 }
diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_trans/cabi_asmjs.rs
index f410627400c34..b0ee016da7fa1 100644
--- a/src/librustc_trans/cabi_asmjs.rs
+++ b/src/librustc_trans/cabi_asmjs.rs
@@ -8,10 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use llvm::{Struct, Array};
-use abi::{FnType, ArgType, ArgAttribute};
+use abi::{FnType, ArgType, ArgAttribute, LayoutExt, Uniform};
 use context::CrateContext;
 
 // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
@@ -19,31 +16,31 @@ use context::CrateContext;
 // See the https://github.com/kripken/emscripten-fastcomp-clang repository.
 // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    match ret.ty.kind() {
-        Struct => {
-            let field_types = ret.ty.field_types();
-            if field_types.len() == 1 {
-                ret.cast = Some(field_types[0]);
-            } else {
-                ret.make_indirect(ccx);
-            }
-        }
-        Array => {
-            ret.make_indirect(ccx);
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if let Some(unit) = ret.layout.homogenous_aggregate(ccx) {
+        let size = ret.layout.size(ccx);
+        if unit.size == size {
+            ret.cast_to(ccx, Uniform {
+                unit,
+                total: size
+            });
+            return;
         }
-        _ => {}
+    }
+
+    if ret.layout.is_aggregate() {
+        ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.is_aggregate() {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() {
         arg.make_indirect(ccx);
         arg.attrs.set(ArgAttribute::ByVal);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_trans/cabi_mips.rs
index 25fe53e7ef40f..b7b60859d4a04 100644
--- a/src/librustc_trans/cabi_mips.rs
+++ b/src/librustc_trans/cabi_mips.rs
@@ -8,94 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
 use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 4)
-}
 
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 4)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
 
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i32());
+        }
     } else {
         arg.extend_integer_width_to(32);
     }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i32(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i32(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 32;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
 
-    let r = size % 32;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
-        }
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs
index e6b500c88dc7a..dff75e628de10 100644
--- a/src/librustc_trans/cabi_mips64.rs
+++ b/src/librustc_trans/cabi_mips64.rs
@@ -8,94 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
 use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 8)
-}
 
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 8)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(64);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
 
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i64(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i64());
+        }
     } else {
         arg.extend_integer_width_to(64);
     }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i64(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i64(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 64;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
 
-    let r = size % 64;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
-        }
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_trans/cabi_msp430.rs
index aa90bb7ab753a..546bb5ad9b44e 100644
--- a/src/librustc_trans/cabi_msp430.rs
+++ b/src/librustc_trans/cabi_msp430.rs
@@ -11,17 +11,8 @@
 // Reference: MSP430 Embedded Application Binary Interface
 // http://www.ti.com/lit/an/slaa534/slaa534.pdf
 
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 2)
-}
 
 // 3.5 Structures or Unions Passed and Returned by Reference
 //
@@ -29,23 +20,23 @@ fn ty_size(ty: Type) -> usize {
 // returned by reference. To pass a structure or union by reference, the caller
 // places its address in the appropriate location: either in a register or on
 // the stack, according to its position in the argument list. (..)"
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 {
         ret.make_indirect(ccx);
     } else {
         ret.extend_integer_width_to(16);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 {
         arg.make_indirect(ccx);
     } else {
         arg.extend_integer_width_to(16);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_nvptx.rs b/src/librustc_trans/cabi_nvptx.rs
index 5ece19f764a8a..3873752b25470 100644
--- a/src/librustc_trans/cabi_nvptx.rs
+++ b/src/librustc_trans/cabi_nvptx.rs
@@ -11,35 +11,26 @@
 // Reference: PTX Writer's Guide to Interoperability
 // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
 
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 4)
-}
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 {
         ret.make_indirect(ccx);
     } else {
         ret.extend_integer_width_to(32);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 {
         arg.make_indirect(ccx);
     } else {
         arg.extend_integer_width_to(32);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_nvptx64.rs b/src/librustc_trans/cabi_nvptx64.rs
index 880c6cfd7a8ac..24bf4920c16c1 100644
--- a/src/librustc_trans/cabi_nvptx64.rs
+++ b/src/librustc_trans/cabi_nvptx64.rs
@@ -11,35 +11,26 @@
 // Reference: PTX Writer's Guide to Interoperability
 // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
 
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 8)
-}
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 {
         ret.make_indirect(ccx);
     } else {
         ret.extend_integer_width_to(64);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 {
         arg.make_indirect(ccx);
     } else {
         arg.extend_integer_width_to(64);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs
index 4e1d7a9337827..f951ac76391f6 100644
--- a/src/librustc_trans/cabi_powerpc.rs
+++ b/src/librustc_trans/cabi_powerpc.rs
@@ -8,100 +8,41 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc::c_uint;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, FnType, ArgType};
+use abi::{align_up_to, FnType, ArgType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
 
 use std::cmp;
 
-fn ty_align(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_align(ty, 4)
-    }
-}
-
-fn ty_size(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_size(ty, 4)
-    }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
 
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i32());
+        }
     } else {
         arg.extend_integer_width_to(32);
     }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => true,
-        _ => false
-    };
-}
 
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i32(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i32(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 32;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
-
-    let r = size % 32;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
-        }
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs
index cdc7c1fd1afb3..c4f8d0b4b9637 100644
--- a/src/librustc_trans/cabi_powerpc64.rs
+++ b/src/librustc_trans/cabi_powerpc64.rs
@@ -8,100 +8,42 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME: The PowerPC64 ABI needs to zero or sign extend function
-// call parameters, but compute_abi_info() is passed LLVM types
-// which have no sign information.
-//
+// FIXME:
 // Alignment of 128 bit types is not currently handled, this will
 // need to be fixed when PowerPC vector support is added.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_size(ty, 8)
-    }
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
-    fn check_array(ty: Type) -> Option<(Type, u64)> {
-        let len = ty.array_length() as u64;
-        if len == 0 {
-            return None
-        }
-        let elt = ty.element_type();
-
-        // if our element is an HFA/HVA, so are we; multiply members by our len
-        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
-    }
 
-    fn check_struct(ty: Type) -> Option<(Type, u64)> {
-        let str_tys = ty.field_types();
-        if str_tys.len() == 0 {
-            return None
-        }
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+                                     -> Option<Uniform> {
+    arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+        let size = arg.layout.size(ccx);
 
-        let mut prev_base_ty = None;
-        let mut members = 0;
-        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
-            match (prev_base_ty, opt_homog_agg) {
-                // field isn't itself an HFA, so we aren't either
-                (_, None) => return None,
-
-                // first field - store its type and number of members
-                (None, Some((field_ty, field_members))) => {
-                    prev_base_ty = Some(field_ty);
-                    members = field_members;
-                },
-
-                // 2nd or later field - give up if it's a different type; otherwise incr. members
-                (Some(prev_ty), Some((field_ty, field_members))) => {
-                    if prev_ty != field_ty {
-                        return None;
-                    }
-                    members += field_members;
-                }
-            }
+        // Ensure we have at most eight uniquely addressable members.
+        if size > unit.size.checked_mul(8, ccx).unwrap() {
+            return None;
         }
 
-        // Because of previous checks, we know prev_base_ty is Some(...) because
-        //   1. str_tys has at least one element; and
-        //   2. prev_base_ty was filled in (or we would've returned early)
-        let (base_ty, members) = (prev_base_ty.unwrap(), members);
-
-        // Ensure there is no padding.
-        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
-            Some((base_ty, members))
-        } else {
-            None
-        }
-    }
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 128
+        };
 
-    let homog_agg = match ty.kind() {
-        Float  => Some((ty, 1)),
-        Double => Some((ty, 1)),
-        Array  => check_array(ty),
-        Struct => check_struct(ty),
-        _ => None
-    };
-
-    // Ensure we have at most eight uniquely addressable members
-    homog_agg.and_then(|(base_ty, members)| {
-        if members > 0 && members <= 8 {
-            Some((base_ty, members))
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
         } else {
             None
         }
     })
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(64);
         return;
     }
@@ -111,78 +53,52 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
         ret.make_indirect(ccx);
     }
 
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
-        ret.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+        ret.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(ret.ty);
-    if size <= 16 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        ret.cast = Some(llty);
+
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
 
     ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(64);
         return;
     }
 
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
-        arg.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+        arg.cast_to(ccx, uniform);
         return;
     }
 
-    arg.cast = Some(struct_ty(ccx, arg.ty));
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => true,
-        _ => false
-    }
-}
-
-fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let long_ty = Type::i64(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 64;
-    while n > 0 {
-        args.push(long_ty);
-        n -= 1;
-    }
-
-    let r = size % 64;
-    if r > 0 {
-        args.push(Type::ix(ccx, r as u64));
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+    let total = arg.layout.size(ccx);
+    arg.cast_to(ccx, Uniform {
+        unit: Reg::i64(),
+        total
+    });
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs
index 5a666c6083d16..9a710c7441170 100644
--- a/src/librustc_trans/cabi_s390x.rs
+++ b/src/librustc_trans/cabi_s390x.rs
@@ -11,130 +11,60 @@
 // FIXME: The assumes we're using the non-vector ABI, i.e. compiling
 // for a pre-z13 machine or using -mno-vx.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{align_up_to, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg};
 use context::CrateContext;
-use type_::Type;
 
-use std::cmp;
+use rustc::ty::layout::{self, Layout, TyLayout};
 
-fn align(off: usize, ty: Type) -> usize {
-    let a = ty_align(ty);
-    return align_up_to(off, a);
-}
-
-fn ty_align(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 8,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ty_align(elt)
-        }
-        Vector => ty_size(ty),
-        _ => bug!("ty_align: unhandled type")
-    }
-}
-
-fn ty_size(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 8,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
-                align(size, ty)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() && ret.layout.size(ccx).bits() <= 64 {
         ret.extend_integer_width_to(64);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct {
-        fn is_single_fp_element(tys: &[Type]) -> bool {
-            if tys.len() != 1 {
-                return false;
-            }
-            match tys[0].kind() {
-                Float | Double => true,
-                Struct => is_single_fp_element(&tys[0].field_types()),
-                _ => false
-            }
-        }
-
-        if is_single_fp_element(&arg.ty.field_types()) {
-            match ty_size(arg.ty) {
-                4 => arg.cast = Some(Type::f32(ccx)),
-                8 => arg.cast = Some(Type::f64(ccx)),
-                _ => arg.make_indirect(ccx)
-            }
-        } else {
-            match ty_size(arg.ty) {
-                1 => arg.cast = Some(Type::i8(ccx)),
-                2 => arg.cast = Some(Type::i16(ccx)),
-                4 => arg.cast = Some(Type::i32(ccx)),
-                8 => arg.cast = Some(Type::i64(ccx)),
-                _ => arg.make_indirect(ccx)
+fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                  layout: TyLayout<'tcx>) -> bool {
+    match *layout {
+        Layout::Scalar { value: layout::F32, .. } |
+        Layout::Scalar { value: layout::F64, .. } => true,
+        Layout::Univariant { .. } => {
+            if layout.field_count(ccx) == 1 {
+                is_single_fp_element(ccx, layout.field(ccx, 0))
+            } else {
+                false
             }
         }
-        return;
+        _ => false
     }
+}
 
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    let size = arg.layout.size(ccx);
+    if !arg.layout.is_aggregate() && size.bits() <= 64 {
         arg.extend_integer_width_to(64);
-    } else {
-        arg.make_indirect(ccx);
+        return;
     }
-}
 
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => ty_size(ty) <= 8,
-        _ => false
+    if is_single_fp_element(ccx, arg.layout) {
+        match size.bytes() {
+            4 => arg.cast_to(ccx, Reg::f32()),
+            8 => arg.cast_to(ccx, Reg::f64()),
+            _ => arg.make_indirect(ccx)
+        }
+    } else {
+        match size.bytes() {
+            1 => arg.cast_to(ccx, Reg::i8()),
+            2 => arg.cast_to(ccx, Reg::i16()),
+            4 => arg.cast_to(ccx, Reg::i32()),
+            8 => arg.cast_to(ccx, Reg::i64()),
+            _ => arg.make_indirect(ccx)
+        }
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_sparc.rs b/src/librustc_trans/cabi_sparc.rs
index 25fe53e7ef40f..c17901e1adebc 100644
--- a/src/librustc_trans/cabi_sparc.rs
+++ b/src/librustc_trans/cabi_sparc.rs
@@ -8,94 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
 use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 4)
-}
 
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 4)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
-
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
-    } else {
-        arg.extend_integer_width_to(32);
-    }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i32(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i32(ccx);
-    let mut args = Vec::new();
 
-    let mut n = size / 32;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
-
-    let r = size % 32;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i32());
         }
+    } else {
+        arg.extend_integer_width_to(32)
     }
 
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_sparc64.rs b/src/librustc_trans/cabi_sparc64.rs
index e675cca33d1be..b75fa97f948ec 100644
--- a/src/librustc_trans/cabi_sparc64.rs
+++ b/src/librustc_trans/cabi_sparc64.rs
@@ -10,170 +10,89 @@
 
 // FIXME: This needs an audit for correctness and completeness.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
 use context::CrateContext;
-use type_::Type;
 
-fn ty_size(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_size(ty, 8)
-    }
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
-    fn check_array(ty: Type) -> Option<(Type, u64)> {
-        let len = ty.array_length() as u64;
-        if len == 0 {
-            return None
-        }
-        let elt = ty.element_type();
-
-        // if our element is an HFA/HVA, so are we; multiply members by our len
-        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
-    }
-
-    fn check_struct(ty: Type) -> Option<(Type, u64)> {
-        let str_tys = ty.field_types();
-        if str_tys.len() == 0 {
-            return None
-        }
-
-        let mut prev_base_ty = None;
-        let mut members = 0;
-        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
-            match (prev_base_ty, opt_homog_agg) {
-                // field isn't itself an HFA, so we aren't either
-                (_, None) => return None,
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+                                     -> Option<Uniform> {
+    arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+        let size = arg.layout.size(ccx);
 
-                // first field - store its type and number of members
-                (None, Some((field_ty, field_members))) => {
-                    prev_base_ty = Some(field_ty);
-                    members = field_members;
-                },
-
-                // 2nd or later field - give up if it's a different type; otherwise incr. members
-                (Some(prev_ty), Some((field_ty, field_members))) => {
-                    if prev_ty != field_ty {
-                        return None;
-                    }
-                    members += field_members;
-                }
-            }
+        // Ensure we have at most eight uniquely addressable members.
+        if size > unit.size.checked_mul(8, ccx).unwrap() {
+            return None;
         }
 
-        // Because of previous checks, we know prev_base_ty is Some(...) because
-        //   1. str_tys has at least one element; and
-        //   2. prev_base_ty was filled in (or we would've returned early)
-        let (base_ty, members) = (prev_base_ty.unwrap(), members);
-
-        // Ensure there is no padding.
-        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
-            Some((base_ty, members))
-        } else {
-            None
-        }
-    }
-
-    let homog_agg = match ty.kind() {
-        Float  => Some((ty, 1)),
-        Double => Some((ty, 1)),
-        Array  => check_array(ty),
-        Struct => check_struct(ty),
-        _ => None
-    };
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 128
+        };
 
-    // Ensure we have at most eight uniquely addressable members
-    homog_agg.and_then(|(base_ty, members)| {
-        if members > 0 && members <= 8 {
-            Some((base_ty, members))
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
         } else {
             None
         }
     })
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(64);
         return;
     }
 
-    // don't return aggregates in registers
-    ret.make_indirect(ccx);
-
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
-        ret.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+        ret.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(ret.ty);
-    if size <= 16 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        ret.cast = Some(llty);
+
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
+
+    // don't return aggregates in registers
+    ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(64);
         return;
     }
 
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
-        arg.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+        arg.cast_to(ccx, uniform);
         return;
     }
 
-    arg.cast = Some(struct_ty(ccx, arg.ty));
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => true,
-        _ => false
-    }
-}
-
-fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let long_ty = Type::i64(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 64;
-    while n > 0 {
-        args.push(long_ty);
-        n -= 1;
-    }
-
-    let r = size % 64;
-    if r > 0 {
-        args.push(Type::ix(ccx, r as u64));
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+    let total = arg.layout.size(ccx);
+    arg.cast_to(ccx, Uniform {
+        unit: Reg::i64(),
+        total
+    });
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs
index fea005f3d77da..9f5520dabe334 100644
--- a/src/librustc_trans/cabi_x86.rs
+++ b/src/librustc_trans/cabi_x86.rs
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::*;
-use abi::{ArgAttribute, FnType};
-use type_::Type;
-use super::common::*;
-use super::machine::*;
+use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind};
+use common::CrateContext;
 
 #[derive(PartialEq)]
 pub enum Flavor {
@@ -20,9 +17,11 @@ pub enum Flavor {
     Fastcall
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                  fty: &mut FnType<'tcx>,
+                                  flavor: Flavor) {
     if !fty.ret.is_ignore() {
-        if fty.ret.ty.kind() == Struct {
+        if fty.ret.layout.is_aggregate() {
             // Returning a structure. Most often, this will use
             // a hidden first argument. On some platforms, though,
             // small structs are returned as integers.
@@ -33,11 +32,12 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
             let t = &ccx.sess().target.target;
             if t.options.is_like_osx || t.options.is_like_windows
                 || t.options.is_like_openbsd {
-                match llsize_of_alloc(ccx, fty.ret.ty) {
-                    1 => fty.ret.cast = Some(Type::i8(ccx)),
-                    2 => fty.ret.cast = Some(Type::i16(ccx)),
-                    4 => fty.ret.cast = Some(Type::i32(ccx)),
-                    8 => fty.ret.cast = Some(Type::i64(ccx)),
+                let size = fty.ret.layout.size(ccx);
+                match size.bytes() {
+                    1 => fty.ret.cast_to(ccx, Reg::i8()),
+                    2 => fty.ret.cast_to(ccx, Reg::i16()),
+                    4 => fty.ret.cast_to(ccx, Reg::i32()),
+                    8 => fty.ret.cast_to(ccx, Reg::i64()),
                     _ => fty.ret.make_indirect(ccx)
                 }
             } else {
@@ -50,7 +50,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        if arg.ty.kind() == Struct {
+        if arg.layout.is_aggregate() {
             arg.make_indirect(ccx);
             arg.attrs.set(ArgAttribute::ByVal);
         } else {
@@ -73,12 +73,15 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
         for arg in &mut fty.args {
             if arg.is_ignore() || arg.is_indirect() { continue; }
 
-            if arg.ty.kind() == Float {
+            // At this point we know this must be a primitive of sorts.
+            let unit = arg.layout.homogenous_aggregate(ccx).unwrap();
+            let size = arg.layout.size(ccx);
+            assert_eq!(unit.size, size);
+            if unit.kind == RegKind::Float {
                 continue;
             }
 
-            let size = llbitsize_of_real(ccx, arg.ty);
-            let size_in_regs = (size + 31) / 32;
+            let size_in_regs = (size.bits() + 31) / 32;
 
             if size_in_regs == 0 {
                 continue;
@@ -90,7 +93,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
 
             free_regs -= size_in_regs;
 
-            if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
+            if size.bits() <= 32 && unit.kind == RegKind::Integer {
                 arg.attrs.set(ArgAttribute::InReg);
             }
 
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 7f2fdbf000b65..bb56378fd58aa 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -11,388 +11,260 @@
 // The classification code for the x86_64 ABI is taken from the clay language
 // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
 
-#![allow(non_upper_case_globals)]
-use self::RegClass::*;
-
-use llvm::{Integer, Pointer, Float, Double};
-use llvm::{Struct, Array, Vector};
-use abi::{self, ArgType, ArgAttribute, FnType};
+use abi::{ArgType, ArgAttribute, FnType, LayoutExt, Reg, RegKind};
 use context::CrateContext;
-use type_::Type;
 
-#[derive(Clone, Copy, PartialEq)]
-enum RegClass {
-    NoClass,
+use rustc::ty::layout::{self, Layout, TyLayout, Size};
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+enum Class {
+    None,
     Int,
-    SSEFs,
-    SSEFv,
-    SSEDs,
-    SSEDv,
-    SSEInt(/* bitwidth */ u64),
+    LoneF32,
+    Sse,
     /// Data that can appear in the upper half of an SSE register.
-    SSEUp,
-    X87,
-    X87Up,
-    ComplexX87,
-    Memory
+    SseUp
 }
 
-trait TypeMethods {
-    fn is_reg_ty(&self) -> bool;
-}
+#[derive(Clone, Copy, Debug)]
+struct Memory;
 
-impl TypeMethods for Type {
-    fn is_reg_ty(&self) -> bool {
-        match self.kind() {
-            Integer | Pointer | Float | Double => true,
-            _ => false
-        }
-    }
-}
+// Currently supported vector size (AVX).
+const LARGEST_VECTOR_SIZE: usize = 256;
+const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
 
-impl RegClass {
-    fn is_sse(&self) -> bool {
-        match *self {
-            SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
-            _ => false
-        }
-    }
-}
-
-trait ClassList {
-    fn is_pass_byval(&self) -> bool;
-    fn is_ret_bysret(&self) -> bool;
-}
-
-impl ClassList for [RegClass] {
-    fn is_pass_byval(&self) -> bool {
-        if self.is_empty() { return false; }
+fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
+                          -> Result<[Class; MAX_EIGHTBYTES], Memory> {
+    fn unify(cls: &mut [Class],
+             off: u64,
+             c: Class) {
+        let i = (off / 8) as usize;
+        let to_write = match (cls[i], c) {
+            (Class::None, _) => c,
+            (_, Class::None) => return,
 
-        let class = self[0];
-           class == Memory
-        || class == X87
-        || class == ComplexX87
-    }
+            (Class::Int, _) |
+            (_, Class::Int) => Class::Int,
 
-    fn is_ret_bysret(&self) -> bool {
-        if self.is_empty() { return false; }
-
-        self[0] == Memory
-    }
-}
-
-fn classify_ty(ty: Type) -> Vec<RegClass> {
-    fn align(off: usize, ty: Type) -> usize {
-        let a = ty_align(ty);
-        return (off + a - 1) / a * a;
-    }
-
-    fn ty_align(ty: Type) -> usize {
-        abi::ty_align(ty, 8)
-    }
-
-    fn ty_size(ty: Type) -> usize {
-        abi::ty_size(ty, 8)
-    }
-
-    fn all_mem(cls: &mut [RegClass]) {
-        for elt in cls {
-            *elt = Memory;
-        }
-    }
+            (Class::LoneF32, Class::LoneF32) => Class::LoneF32,
 
-    fn unify(cls: &mut [RegClass],
-             i: usize,
-             newv: RegClass) {
-        if cls[i] == newv { return }
+            (Class::Sse, _) |
+            (_, Class::Sse) |
+            (Class::LoneF32, _) |
+            (_, Class::LoneF32) => Class::Sse,
 
-        let to_write = match (cls[i], newv) {
-            (NoClass,     _) => newv,
-            (_,           NoClass) => return,
-
-            (Memory,      _) |
-            (_,           Memory) => Memory,
-
-            (Int,         _) |
-            (_,           Int) => Int,
-
-            (X87,         _) |
-            (X87Up,       _) |
-            (ComplexX87,  _) |
-            (_,           X87) |
-            (_,           X87Up) |
-            (_,           ComplexX87) => Memory,
-
-            (SSEFv,       SSEUp) |
-            (SSEFs,       SSEUp) |
-            (SSEDv,       SSEUp) |
-            (SSEDs,       SSEUp) |
-            (SSEInt(_),   SSEUp) => return,
-
-            (..) => newv
+            (Class::SseUp, Class::SseUp) => Class::SseUp
         };
         cls[i] = to_write;
     }
 
-    fn classify_struct(tys: &[Type],
-                       cls: &mut [RegClass],
-                       i: usize,
-                       off: usize,
-                       packed: bool) {
-        let mut field_off = off;
-        for ty in tys {
-            if !packed {
-                field_off = align(field_off, *ty);
+    fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                          layout: TyLayout<'tcx>,
+                          cls: &mut [Class],
+                          off: u64)
+                          -> Result<(), Memory> {
+        if off % layout.align(ccx).abi() != 0 {
+            if layout.size(ccx).bytes() > 0 {
+                return Err(Memory);
             }
-            classify(*ty, cls, i, field_off);
-            field_off += ty_size(*ty);
+            return Ok(());
         }
-    }
 
-    fn classify(ty: Type,
-                cls: &mut [RegClass], ix: usize,
-                off: usize) {
-        let t_align = ty_align(ty);
-        let t_size = ty_size(ty);
-
-        let misalign = off % t_align;
-        if misalign != 0 {
-            let mut i = off / 8;
-            let e = (off + t_size + 7) / 8;
-            while i < e {
-                unify(cls, ix + i, Memory);
-                i += 1;
+        match *layout {
+            Layout::Scalar { value, .. } |
+            Layout::RawNullablePointer { value, .. } => {
+                let reg = match value {
+                    layout::Int(_) |
+                    layout::Pointer => Class::Int,
+                    layout::F32 => {
+                        if off % 8 == 0 {
+                            Class::LoneF32
+                        } else {
+                            Class::Sse
+                        }
+                    }
+                    layout::F64 => Class::Sse
+                };
+                unify(cls, off, reg);
             }
-            return;
-        }
 
-        match ty.kind() {
-            Integer |
-            Pointer => {
-                unify(cls, ix + off / 8, Int);
+            Layout::CEnum { .. } => {
+                unify(cls, off, Class::Int);
             }
-            Float => {
-                if off % 8 == 4 {
-                    unify(cls, ix + off / 8, SSEFv);
-                } else {
-                    unify(cls, ix + off / 8, SSEFs);
+
+            Layout::Vector { element, count } => {
+                unify(cls, off, Class::Sse);
+
+                // everything after the first one is the upper
+                // half of a register.
+                let eltsz = element.size(ccx).bytes();
+                for i in 1..count {
+                    unify(cls, off + i * eltsz, Class::SseUp);
                 }
             }
-            Double => {
-                unify(cls, ix + off / 8, SSEDs);
-            }
-            Struct => {
-                classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
-            }
-            Array => {
-                let len = ty.array_length();
-                let elt = ty.element_type();
-                let eltsz = ty_size(elt);
-                let mut i = 0;
-                while i < len {
-                    classify(elt, cls, ix, off + i * eltsz);
-                    i += 1;
+
+            Layout::Array { count, .. } => {
+                if count > 0 {
+                    let elt = layout.field(ccx, 0);
+                    let eltsz = elt.size(ccx).bytes();
+                    for i in 0..count {
+                        classify(ccx, elt, cls, off + i * eltsz)?;
+                    }
                 }
             }
-            Vector => {
-                let len = ty.vector_length();
-                let elt = ty.element_type();
-                let eltsz = ty_size(elt);
-                let mut reg = match elt.kind() {
-                    Integer => SSEInt(elt.int_width()),
-                    Float => SSEFv,
-                    Double => SSEDv,
-                    _ => bug!("classify: unhandled vector element type")
-                };
 
-                let mut i = 0;
-                while i < len {
-                    unify(cls, ix + (off + i * eltsz) / 8, reg);
+            Layout::Univariant { ref variant, .. } => {
+                for i in 0..layout.field_count(ccx) {
+                    let field_off = off + variant.offsets[i].bytes();
+                    classify(ccx, layout.field(ccx, i), cls, field_off)?;
+                }
+            }
 
-                    // everything after the first one is the upper
-                    // half of a register.
-                    reg = SSEUp;
-                    i += 1;
+            Layout::UntaggedUnion { .. } => {
+                for i in 0..layout.field_count(ccx) {
+                    classify(ccx, layout.field(ccx, i), cls, off)?;
                 }
             }
-            _ => bug!("classify: unhandled type")
+
+            Layout::FatPointer { .. } |
+            Layout::General { .. } |
+            Layout::StructWrappedNullablePointer { .. } => return Err(Memory)
         }
+
+        Ok(())
     }
 
-    fn fixup(ty: Type, cls: &mut [RegClass]) {
+    let n = ((arg.layout.size(ccx).bytes() + 7) / 8) as usize;
+    if n > MAX_EIGHTBYTES {
+        return Err(Memory);
+    }
+
+    let mut cls = [Class::None; MAX_EIGHTBYTES];
+    classify(ccx, arg.layout, &mut cls, 0)?;
+    if n > 2 {
+        if cls[0] != Class::Sse {
+            return Err(Memory);
+        }
+        if cls[1..n].iter().any(|&c| c != Class::SseUp) {
+            return Err(Memory);
+        }
+    } else {
         let mut i = 0;
-        let ty_kind = ty.kind();
-        let e = cls.len();
-        if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
-            if cls[i].is_sse() {
+        while i < n {
+            if cls[i] == Class::SseUp {
+                cls[i] = Class::Sse;
+            } else if cls[i] == Class::Sse {
                 i += 1;
-                while i < e {
-                    if cls[i] != SSEUp {
-                        all_mem(cls);
-                        return;
-                    }
-                    i += 1;
-                }
+                while i != n && cls[i] == Class::SseUp { i += 1; }
             } else {
-                all_mem(cls);
-                return
-            }
-        } else {
-            while i < e {
-                if cls[i] == Memory {
-                    all_mem(cls);
-                    return;
-                }
-                if cls[i] == X87Up {
-                    // for darwin
-                    // cls[i] = SSEDs;
-                    all_mem(cls);
-                    return;
-                }
-                if cls[i] == SSEUp {
-                    cls[i] = SSEDv;
-                } else if cls[i].is_sse() {
-                    i += 1;
-                    while i != e && cls[i] == SSEUp { i += 1; }
-                } else if cls[i] == X87 {
-                    i += 1;
-                    while i != e && cls[i] == X87Up { i += 1; }
-                } else {
-                    i += 1;
-                }
+                i += 1;
             }
         }
     }
 
-    let words = (ty_size(ty) + 7) / 8;
-    let mut cls = vec![NoClass; words];
-    if words > 4 {
-        all_mem(&mut cls);
-        return cls;
-    }
-    classify(ty, &mut cls, 0, 0);
-    fixup(ty, &mut cls);
-    return cls;
+    Ok(cls)
 }
 
-fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
-    fn llvec_len(cls: &[RegClass]) -> usize {
-        let mut len = 1;
-        for c in cls {
-            if *c != SSEUp {
-                break;
-            }
-            len += 1;
-        }
-        return len;
+fn reg_component(cls: &[Class], i: &mut usize) -> Option<Reg> {
+    if *i >= cls.len() {
+        return None;
     }
 
-    let mut tys = Vec::new();
-    let mut i = 0;
-    let e = cls.len();
-    while i < e {
-        match cls[i] {
-            Int => {
-                tys.push(Type::i64(ccx));
-            }
-            SSEFv | SSEDv | SSEInt(_) => {
-                let (elts_per_word, elt_ty) = match cls[i] {
-                    SSEFv => (2, Type::f32(ccx)),
-                    SSEDv => (1, Type::f64(ccx)),
-                    SSEInt(bits) => {
-                        assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
-                                "llreg_ty: unsupported SSEInt width {}", bits);
-                        (64 / bits, Type::ix(ccx, bits))
-                    }
-                    _ => bug!(),
-                };
-                let vec_len = llvec_len(&cls[i + 1..]);
-                let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
-                tys.push(vec_ty);
-                i += vec_len;
-                continue;
-            }
-            SSEFs => {
-                tys.push(Type::f32(ccx));
-            }
-            SSEDs => {
-                tys.push(Type::f64(ccx));
-            }
-            _ => bug!("llregtype: unhandled class")
+    match cls[*i] {
+        Class::None => None,
+        Class::Int => {
+            *i += 1;
+            Some(Reg::i64())
+        }
+        Class::LoneF32 => {
+            *i += 1;
+            Some(Reg::f32())
+        }
+        Class::Sse => {
+            let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
+            *i += vec_len;
+            Some(if vec_len == 1 {
+                Reg::f64()
+            } else {
+                Reg {
+                    kind: RegKind::Vector,
+                    size: Size::from_bytes(vec_len as u64 * 8)
+                }
+            })
         }
-        i += 1;
+        c => bug!("reg_component: unhandled class {:?}", c)
     }
-    if tys.len() == 1 && tys[0].kind() == Vector {
-        // if the type contains only a vector, pass it as that vector.
-        tys[0]
+}
+
+fn cast_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                      arg: &mut ArgType<'tcx>,
+                      cls: &[Class]) {
+    let mut i = 0;
+    let lo = reg_component(cls, &mut i).unwrap();
+    if let Some(hi) = reg_component(cls, &mut i) {
+        arg.cast_to(ccx, (lo, hi));
     } else {
-        Type::struct_(ccx, &tys, false)
+        arg.cast_to(ccx, lo)
     }
+    assert_eq!(reg_component(cls, &mut i), None);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    fn x86_64_ty<F>(ccx: &CrateContext,
-                    arg: &mut ArgType,
-                    is_mem_cls: F,
-                    ind_attr: Option<ArgAttribute>)
-        where F: FnOnce(&[RegClass]) -> bool
-    {
-        if !arg.ty.is_reg_ty() {
-            let cls = classify_ty(arg.ty);
-            if is_mem_cls(&cls) {
-                arg.make_indirect(ccx);
-                if let Some(attr) = ind_attr {
-                    arg.attrs.set(attr);
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
+    let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
+    let mut sse_regs = 8; // XMM0-7
+
+    let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| {
+        let cls = classify_arg(ccx, arg);
+
+        let mut needed_int = 0;
+        let mut needed_sse = 0;
+        let in_mem = match cls {
+            Err(Memory) => true,
+            Ok(ref cls) if is_arg => {
+                for &c in cls {
+                    match c {
+                        Class::Int => {
+                            needed_int += 1;
+                        }
+                        Class::LoneF32 | Class::Sse => {
+                            needed_sse += 1;
+                        }
+                        _ => {}
+                    }
                 }
-            } else {
-                arg.cast = Some(llreg_ty(ccx, &cls));
+                arg.layout.is_aggregate() &&
+                    (int_regs < needed_int || sse_regs < needed_sse)
             }
-        } else {
-            arg.extend_integer_width_to(32);
-        }
-    }
+            Ok(_) => false
+        };
 
-    let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
-    let mut sse_regs = 8; // XMM0-7
+        if in_mem {
+            // `sret` / `byval` parameter thus one less integer register available
+            int_regs -= 1;
 
-    if !fty.ret.is_ignore() {
-        x86_64_ty(ccx, &mut fty.ret, |cls| {
-            if cls.is_ret_bysret() {
-                // `sret` parameter thus one less register available
-                int_regs -= 1;
-                true
+            arg.make_indirect(ccx);
+            if is_arg {
+                arg.attrs.set(ArgAttribute::ByVal);
+            }
+        } else {
+            // split into sized chunks passed individually
+            int_regs -= needed_int;
+            sse_regs -= needed_sse;
+
+            if arg.layout.is_aggregate() {
+                cast_arg(ccx, arg, cls.as_ref().unwrap());
             } else {
-                false
+                arg.extend_integer_width_to(32);
             }
-        }, None);
+        }
+    };
+
+    if !fty.ret.is_ignore() {
+        x86_64_ty(&mut fty.ret, false);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        x86_64_ty(ccx, arg, |cls| {
-            let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
-            let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
-            let in_mem = cls.is_pass_byval() ||
-                         int_regs < needed_int ||
-                         sse_regs < needed_sse;
-            if in_mem {
-                // `byval` parameter thus one less integer register available
-                int_regs -= 1;
-            } else {
-                // split into sized chunks passed individually
-                int_regs -= needed_int;
-                sse_regs -= needed_sse;
-            }
-            in_mem
-        }, Some(ArgAttribute::ByVal));
-
-        // An integer, pointer, double or float parameter
-        // thus the above closure passed to `x86_64_ty` won't
-        // get called.
-        match arg.ty.kind() {
-            Integer | Pointer => int_regs -= 1,
-            Double | Float => sse_regs -= 1,
-            _ => {}
-        }
+        x86_64_ty(arg, true);
     }
 }
diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs
index a849f38247380..39e728d4e4f9b 100644
--- a/src/librustc_trans/cabi_x86_win64.rs
+++ b/src/librustc_trans/cabi_x86_win64.rs
@@ -8,30 +8,33 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::*;
-use super::common::*;
-use super::machine::*;
-use abi::{ArgType, FnType};
-use type_::Type;
+use abi::{ArgType, FnType, LayoutExt, Reg};
+use common::CrateContext;
+
+use rustc::ty::layout::Layout;
 
 // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    let fixup = |a: &mut ArgType| {
-        match a.ty.kind() {
-            Struct => match llsize_of_alloc(ccx, a.ty) {
-                          1 => a.cast = Some(Type::i8(ccx)),
-                          2 => a.cast = Some(Type::i16(ccx)),
-                          4 => a.cast = Some(Type::i32(ccx)),
-                          8 => a.cast = Some(Type::i64(ccx)),
-                          _ => a.make_indirect(ccx)
-                      },
-            Integer => match llsize_of_alloc(ccx, a.ty) {
-                           1 ... 8 => a.extend_integer_width_to(32),
-                           16 => a.make_indirect(ccx),
-                           _ => bug!(),
-            },
-            _ => (),
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
+    let fixup = |a: &mut ArgType<'tcx>| {
+        let size = a.layout.size(ccx);
+        if a.layout.is_aggregate() {
+            match size.bits() {
+                8 => a.cast_to(ccx, Reg::i8()),
+                16 => a.cast_to(ccx, Reg::i16()),
+                32 => a.cast_to(ccx, Reg::i32()),
+                64 => a.cast_to(ccx, Reg::i64()),
+                _ => a.make_indirect(ccx)
+            };
+        } else {
+            if let Layout::Vector { .. } = *a.layout {
+                // FIXME(eddyb) there should be a size cap here
+                // (probably what clang calls "illegal vectors").
+            } else if size.bytes() > 8 {
+                a.make_indirect(ccx);
+            } else {
+                a.extend_integer_width_to(32);
+            }
         }
     };
 
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 49ab01723231c..c9b2ba976e04a 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -178,7 +178,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     };
                     let llslot = match op.val {
                         Immediate(_) | Pair(..) => {
-                            let llscratch = bcx.alloca(ret.original_ty, "ret");
+                            let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret");
                             self.store_operand(&bcx, llscratch, None, op);
                             llscratch
                         }
@@ -190,7 +190,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     };
                     let load = bcx.load(
                         bcx.pointercast(llslot, cast_ty.ptr_to()),
-                        Some(llalign_of_min(bcx.ccx, ret.ty)));
+                        Some(ret.layout.align(bcx.ccx).abi() as u32));
                     load
                 } else {
                     let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
@@ -516,7 +516,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                             (llargs[0], &llargs[1..])
                         }
                         ReturnDest::Nothing => {
-                            (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..])
+                            (C_undef(fn_ty.ret.memory_ty(bcx.ccx).ptr_to()), &llargs[..])
                         }
                         ReturnDest::IndirectOperand(dst, _) |
                         ReturnDest::Store(dst) => (dst, &llargs[..]),
@@ -535,7 +535,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                             val: Ref(dst, Alignment::AbiAligned),
                             ty: sig.output(),
                         };
-                        self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+                        self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
                     }
 
                     if let Some((_, target)) = *destination {
@@ -574,7 +574,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                             val: Immediate(invokeret),
                             ty: sig.output(),
                         };
-                        self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
+                        self.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op);
                     }
                 } else {
                     let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle);
@@ -584,7 +584,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                             val: Immediate(llret),
                             ty: sig.output(),
                         };
-                        self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+                        self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
                         funclet_br(self, bcx, target);
                     } else {
                         bcx.unreachable();
@@ -598,7 +598,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                       bcx: &Builder<'a, 'tcx>,
                       op: OperandRef<'tcx>,
                       llargs: &mut Vec<ValueRef>,
-                      fn_ty: &FnType,
+                      fn_ty: &FnType<'tcx>,
                       next_idx: &mut usize,
                       llfn: &mut Option<ValueRef>,
                       def: &Option<ty::InstanceDef<'tcx>>) {
@@ -641,7 +641,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         let (mut llval, align, by_ref) = match op.val {
             Immediate(_) | Pair(..) => {
                 if arg.is_indirect() || arg.cast.is_some() {
-                    let llscratch = bcx.alloca(arg.original_ty, "arg");
+                    let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
                     self.store_operand(bcx, llscratch, None, op);
                     (llscratch, Alignment::AbiAligned, true)
                 } else {
@@ -653,7 +653,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
                 // have scary latent bugs around.
 
-                let llscratch = bcx.alloca(arg.original_ty, "arg");
+                let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
                 base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
                 (llscratch, Alignment::AbiAligned, true)
             }
@@ -662,13 +662,13 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
-            if arg.original_ty == Type::i1(bcx.ccx) {
+            if arg.layout.ty == bcx.tcx().types.bool {
                 // We store bools as i8 so we need to truncate to i1.
                 llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None);
-                llval = bcx.trunc(llval, arg.original_ty);
+                llval = bcx.trunc(llval, Type::i1(bcx.ccx));
             } else if let Some(ty) = arg.cast {
                 llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()),
-                                 align.min_with(llalign_of_min(bcx.ccx, arg.ty)));
+                                 align.min_with(arg.layout.align(bcx.ccx).abi() as u32));
             } else {
                 llval = bcx.load(llval, align.to_align());
             }
@@ -681,7 +681,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                                 bcx: &Builder<'a, 'tcx>,
                                 operand: &mir::Operand<'tcx>,
                                 llargs: &mut Vec<ValueRef>,
-                                fn_ty: &FnType,
+                                fn_ty: &FnType<'tcx>,
                                 next_idx: &mut usize,
                                 llfn: &mut Option<ValueRef>,
                                 def: &Option<ty::InstanceDef<'tcx>>) {
@@ -920,7 +920,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
     fn store_return(&mut self,
                     bcx: &Builder<'a, 'tcx>,
                     dest: ReturnDest,
-                    ret_ty: ArgType,
+                    ret_ty: &ArgType<'tcx>,
                     op: OperandRef<'tcx>) {
         use self::ReturnDest::*;
 
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 8b5bdb6a31a1e..7bf283a75fa68 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -53,7 +53,7 @@ pub struct MirContext<'a, 'tcx:'a> {
 
     ccx: &'a CrateContext<'a, 'tcx>,
 
-    fn_ty: FnType,
+    fn_ty: FnType<'tcx>,
 
     /// When unwinding is initiated, we have to store this personality
     /// value somewhere so that we can load it and re-use it in the
@@ -461,6 +461,23 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 assert_eq!((meta.cast, meta.pad), (None, None));
                 let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
                 llarg_idx += 1;
+
+                // FIXME(eddyb) As we can't perfectly represent the data and/or
+                // vtable pointer in a fat pointers in Rust's typesystem, and
+                // because we split fat pointers into two ArgType's, they're
+                // not the right type so we have to cast them for now.
+                let pointee = match arg_ty.sty {
+                    ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
+                    ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => ty,
+                    ty::TyAdt(def, _) if def.is_box() => arg_ty.boxed_ty(),
+                    _ => bug!()
+                };
+                let data_llty = type_of::in_memory_type_of(bcx.ccx, pointee);
+                let meta_llty = type_of::unsized_info_ty(bcx.ccx, pointee);
+
+                let llarg = bcx.pointercast(llarg, data_llty.ptr_to());
+                let llmeta = bcx.pointercast(llmeta, meta_llty);
+
                 OperandValue::Pair(llarg, llmeta)
             } else {
                 OperandValue::Immediate(llarg)
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index c459191561dd6..d4ab6b0782855 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -19,122 +19,6 @@ use type_::Type;
 
 use syntax::ast;
 
-
-// A "sizing type" is an LLVM type, the size and alignment of which are
-// guaranteed to be equivalent to what you would get out of `type_of()`. It's
-// useful because:
-//
-// (1) It may be cheaper to compute the sizing type than the full type if all
-//     you're interested in is the size and/or alignment;
-//
-// (2) It won't make any recursive calls to determine the structure of the
-//     type behind pointers. This can help prevent infinite loops for
-//     recursive types. For example, enum types rely on this behavior.
-
-pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
-    if let Some(t) = cx.llsizingtypes().borrow().get(&t).cloned() {
-        return t;
-    }
-
-    debug!("sizing_type_of {:?}", t);
-    let _recursion_lock = cx.enter_type_of(t);
-
-    let ptr_sizing_ty = |ty: Ty<'tcx>| {
-        if cx.shared().type_is_sized(ty) {
-            Type::i8p(cx)
-        } else {
-            Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false)
-        }
-    };
-    let llsizingty = match t.sty {
-        _ if !cx.shared().type_is_sized(t) => {
-            Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false)
-        }
-
-        ty::TyBool => Type::bool(cx),
-        ty::TyChar => Type::char(cx),
-        ty::TyInt(t) => Type::int_from_ty(cx, t),
-        ty::TyUint(t) => Type::uint_from_ty(cx, t),
-        ty::TyFloat(t) => Type::float_from_ty(cx, t),
-        ty::TyNever => Type::nil(cx),
-
-        ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
-        ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
-            ptr_sizing_ty(ty)
-        }
-        ty::TyAdt(def, _) if def.is_box() => {
-            ptr_sizing_ty(t.boxed_ty())
-        }
-
-        ty::TyFnDef(..) => Type::nil(cx),
-        ty::TyFnPtr(_) => Type::i8p(cx),
-
-        ty::TyArray(ty, size) => {
-            let llty = sizing_type_of(cx, ty);
-            let size = size as u64;
-            Type::array(&llty, size)
-        }
-
-        ty::TyTuple(ref tys, _) if tys.is_empty() => {
-            Type::nil(cx)
-        }
-
-        ty::TyAdt(..) if t.is_simd() => {
-            let e = t.simd_type(cx.tcx());
-            if !e.is_machine() {
-                cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
-                                          a non-machine element type `{}`",
-                                         t, e))
-            }
-            let llet = type_of(cx, e);
-            let n = t.simd_size(cx.tcx()) as u64;
-            Type::vector(&llet, n)
-        }
-
-        ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => {
-            adt::sizing_type_of(cx, t, false)
-        }
-
-        ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
-        ty::TyAnon(..) | ty::TyError => {
-            bug!("fictitious type {:?} in sizing_type_of()", t)
-        }
-        ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!()
-    };
-
-    debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
-
-    cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
-
-    // FIXME(eddyb) Temporary sanity check for ty::layout.
-    let layout = cx.layout_of(t);
-    if !cx.shared().type_is_sized(t) {
-        if !layout.is_unsized() {
-            bug!("layout should be unsized for type `{}` / {:#?}",
-                 t, layout);
-        }
-
-        // Unsized types get turned into a fat pointer for LLVM.
-        return llsizingty;
-    }
-
-    let r = layout.size(cx).bytes();
-    let l = machine::llsize_of_alloc(cx, llsizingty);
-    if r != l {
-        bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
-             r, l, t, layout);
-    }
-
-    let r = layout.align(cx).abi();
-    let l = machine::llalign_of_min(cx, llsizingty) as u64;
-    if r != l {
-        bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
-             r, l, t, layout);
-    }
-
-    llsizingty
-}
-
 pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
     match ty.sty {
         ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
@@ -148,7 +32,7 @@ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
     }
 }
 
-fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
+pub fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
     let unsized_part = ccx.tcx().struct_tail(ty);
     match unsized_part.sty {
         ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
@@ -197,7 +81,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
 /// of that field's type - this is useful for taking the address of
 /// that field and ensuring the struct has the right alignment.
 /// For the LLVM type of a value as a whole, see `type_of`.
-/// NB: If you update this, be sure to update `sizing_type_of()` as well.
 pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
     // Check the cache.
     if let Some(&llty) = cx.lltypes().borrow().get(&t) {
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index 76313b158ab11..bc84ac49da985 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -121,13 +121,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {
 fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly)
+// CHECK: @trait_borrow({}* nonnull, {}* noalias nonnull readonly)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly)
+// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly)
 #[no_mangle]
 fn trait_box(_: Box<Drop>) {
 }

From c2b44a3966c843a6f1358bc35d27ef20bd01f14d Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Tue, 14 Mar 2017 12:22:38 -0700
Subject: [PATCH 05/14] rustbuild: Update bootstrap compiler

Now that we've also updated cargo's release process this commit also changes the
download location of Cargo from Cargos archives back to the static.r-l.o
archives. This should ensure that the Cargo download is the exact Cargo paired
with the rustc that we release.
---
 src/bootstrap/bootstrap.py          | 17 +++++------------
 src/bootstrap/channel.rs            |  2 +-
 src/librustc/lib.rs                 |  1 -
 src/librustc_asan/lib.rs            |  4 ++--
 src/librustc_data_structures/lib.rs |  1 -
 src/librustc_incremental/lib.rs     |  1 -
 src/librustc_lsan/lib.rs            |  4 ++--
 src/librustc_metadata/lib.rs        |  1 -
 src/librustc_mir/lib.rs             |  3 +--
 src/librustc_msan/lib.rs            |  4 ++--
 src/librustc_trans/lib.rs           |  1 -
 src/librustc_tsan/lib.rs            |  4 ++--
 src/librustc_typeck/lib.rs          |  1 -
 src/stage0.txt                      |  3 +--
 src/tools/compiletest/src/main.rs   |  1 -
 15 files changed, 16 insertions(+), 32 deletions(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index b326f95e505fb..d5bc6127a1e7f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -160,11 +160,8 @@ class RustBuild(object):
     def download_stage0(self):
         cache_dst = os.path.join(self.build_dir, "cache")
         rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date())
-        cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev())
         if not os.path.exists(rustc_cache):
             os.makedirs(rustc_cache)
-        if not os.path.exists(cargo_cache):
-            os.makedirs(cargo_cache)
 
         if self.rustc().startswith(self.bin_root()) and \
                 (not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
@@ -195,15 +192,15 @@ def download_stage0(self):
         if self.cargo().startswith(self.bin_root()) and \
                 (not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
             self.print_what_it_means_to_bootstrap()
-            filename = "cargo-nightly-{}.tar.gz".format(self.build)
-            url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev()
-            tarball = os.path.join(cargo_cache, filename)
+            filename = "cargo-{}-{}.tar.gz".format(channel, self.build)
+            url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date()
+            tarball = os.path.join(rustc_cache, filename)
             if not os.path.exists(tarball):
                 get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
             unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose)
             self.fix_executable(self.bin_root() + "/bin/cargo")
             with open(self.cargo_stamp(), 'w') as f:
-                f.write(self.stage0_cargo_rev())
+                f.write(self.stage0_rustc_date())
 
     def fix_executable(self, fname):
         # If we're on NixOS we need to change the path to the dynamic loader
@@ -258,9 +255,6 @@ def fix_executable(self, fname):
             print("warning: failed to call patchelf: %s" % e)
             return
 
-    def stage0_cargo_rev(self):
-        return self._cargo_rev
-
     def stage0_rustc_date(self):
         return self._rustc_date
 
@@ -283,7 +277,7 @@ def cargo_out_of_date(self):
         if not os.path.exists(self.cargo_stamp()) or self.clean:
             return True
         with open(self.cargo_stamp(), 'r') as f:
-            return self.stage0_cargo_rev() != f.read()
+            return self.stage0_rustc_date() != f.read()
 
     def bin_root(self):
         return os.path.join(self.build_dir, self.build, "stage0")
@@ -578,7 +572,6 @@ def bootstrap():
 
     data = stage0_data(rb.rust_root)
     rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1)
-    rb._cargo_rev = data['cargo']
 
     # Fetch/build the bootstrap
     rb.build = rb.build_triple()
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index 2607ce412f108..a95bdcb3d2608 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -23,7 +23,7 @@ use build_helper::output;
 use Build;
 
 // The version number
-pub const CFG_RELEASE_NUM: &'static str = "1.17.0";
+pub const CFG_RELEASE_NUM: &'static str = "1.18.0";
 
 // An optional number to put after the label, e.g. '.2' -> '-beta.2'
 // Be sure to make this starts with a dot to conform to semver pre-release
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index a007c9d2c43a9..c024a37e357e6 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -29,7 +29,6 @@
 #![feature(conservative_impl_trait)]
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
-#![cfg_attr(stage0,feature(field_init_shorthand))]
 #![feature(i128_type)]
 #![feature(libc)]
 #![feature(loop_break_value)]
diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs
index 71a166b91ebcb..54941362e8450 100644
--- a/src/librustc_asan/lib.rs
+++ b/src/librustc_asan/lib.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
-#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![sanitizer_runtime]
+#![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 8ecfd75dc95a9..9ccd95dd8d805 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -27,7 +27,6 @@
 
 #![feature(shared)]
 #![feature(collections_range)]
-#![cfg_attr(stage0,feature(field_init_shorthand))]
 #![feature(nonzero)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 0a8719c125329..53fb3c35312b2 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -24,7 +24,6 @@
 #![feature(rand)]
 #![feature(core_intrinsics)]
 #![feature(conservative_impl_trait)]
-#![cfg_attr(stage0,feature(field_init_shorthand))]
 #![cfg_attr(stage0, feature(pub_restricted))]
 
 extern crate graphviz;
diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs
index 71a166b91ebcb..54941362e8450 100644
--- a/src/librustc_lsan/lib.rs
+++ b/src/librustc_lsan/lib.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
-#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![sanitizer_runtime]
+#![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 0ce886ce9e9df..2fbdb8c0de676 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -20,7 +20,6 @@
 #![feature(box_patterns)]
 #![feature(conservative_impl_trait)]
 #![feature(core_intrinsics)]
-#![cfg_attr(stage0, feature(field_init_shorthand))]
 #![feature(i128_type)]
 #![feature(proc_macro_internals)]
 #![feature(quote)]
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 590c6a430b98a..8b55cdf06d208 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -23,7 +23,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(associated_consts)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![cfg_attr(stage0, feature(field_init_shorthand))]
 #![feature(i128_type)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
@@ -61,4 +60,4 @@ pub fn provide(providers: &mut Providers) {
     mir_map::provide(providers);
     shim::provide(providers);
     transform::qualify_consts::provide(providers);
-}
\ No newline at end of file
+}
diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs
index 71a166b91ebcb..54941362e8450 100644
--- a/src/librustc_msan/lib.rs
+++ b/src/librustc_msan/lib.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
-#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![sanitizer_runtime]
+#![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index f3e30ed4839ae..5c3b17c889760 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -28,7 +28,6 @@
 #![feature(box_syntax)]
 #![feature(const_fn)]
 #![feature(custom_attribute)]
-#![cfg_attr(stage0, feature(field_init_shorthand))]
 #![allow(unused_attributes)]
 #![feature(i128_type)]
 #![feature(libc)]
diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs
index 71a166b91ebcb..54941362e8450 100644
--- a/src/librustc_tsan/lib.rs
+++ b/src/librustc_tsan/lib.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
-#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![sanitizer_runtime]
+#![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index df1c94dc19b59..4c772843afb2c 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -77,7 +77,6 @@ This API is completely unstable and subject to change.
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(conservative_impl_trait)]
-#![cfg_attr(stage0,feature(field_init_shorthand))]
 #![feature(loop_break_value)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/stage0.txt b/src/stage0.txt
index 772029ab0c253..60fbcadf49157 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,5 +12,4 @@
 # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
 # released on `$date`
 
-rustc: beta-2017-02-01
-cargo: 407edef22e894266eb562618cba5ca9757051946
+rustc: beta-2017-03-21
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 5a97f7e3ee9b5..c52d35e209d14 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -12,7 +12,6 @@
 
 #![feature(box_syntax)]
 #![feature(rustc_private)]
-#![feature(static_in_const)]
 #![feature(test)]
 #![feature(libc)]
 

From b47035460f89fec11b9ab1348717e5ab61b16a67 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 23 Mar 2017 16:22:29 -0700
Subject: [PATCH 06/14] Update cargo submodule

I'm not really sure what we want the cadence here to be. We'll at the very least
update the Cargo submodule right before all releases, but otherwise I figured we
could just do it whenever needed or otherwise weekly (or something like that).

In any case, I don't have a super strong particular reason to do this, it's just
been a week or so since the release!
---
 cargo | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cargo b/cargo
index c995e9eb5acf3..4e95c6b41eca3 160000
--- a/cargo
+++ b/cargo
@@ -1 +1 @@
-Subproject commit c995e9eb5acf3976ae8674a0dc6d9e958053d9fd
+Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5

From 50c4222cb5529023f8ae2e65e3d8cb0272bbf41a Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Thu, 16 Mar 2017 10:23:33 +0000
Subject: [PATCH 07/14] Move `syntax::ext::hygiene` to `syntax_pos::hygiene`.

---
 src/librustc/hir/map/def_collector.rs           |  2 +-
 src/librustc_resolve/build_reduced_graph.rs     |  2 +-
 src/libsyntax/ast.rs                            | 10 +++++++++-
 src/libsyntax/ext/expand.rs                     |  6 +++---
 src/libsyntax/ext/placeholders.rs               |  4 ++--
 src/libsyntax/lib.rs                            |  2 +-
 src/{libsyntax/ext => libsyntax_pos}/hygiene.rs | 13 ++++---------
 src/libsyntax_pos/lib.rs                        |  3 +++
 8 files changed, 24 insertions(+), 18 deletions(-)
 rename src/{libsyntax/ext => libsyntax_pos}/hygiene.rs (95%)

diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index cae358a303e02..afdb9059ea7c0 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -92,7 +92,7 @@ impl<'a> DefCollector<'a> {
     fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) {
         if let Some(ref mut visit) = self.visit_macro_invoc {
             visit(MacroInvocationData {
-                mark: Mark::from_placeholder_id(id),
+                mark: id.placeholder_to_mark(),
                 const_expr: const_expr,
                 def_index: self.parent_def.unwrap(),
             })
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index c33d5b9b6e16b..37813afbc344b 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -680,7 +680,7 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
 
 impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
     fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
-        let mark = Mark::from_placeholder_id(id);
+        let mark = id.placeholder_to_mark();
         self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
         let invocation = self.resolver.invocations[&mark];
         invocation.module.set(self.resolver.current_module);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 3dd4bdbd14ddb..7e2b225193f6d 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -20,7 +20,7 @@ pub use util::ThinVec;
 use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId};
 use codemap::{respan, Spanned};
 use abi::Abi;
-use ext::hygiene::SyntaxContext;
+use ext::hygiene::{Mark, SyntaxContext};
 use print::pprust;
 use ptr::P;
 use rustc_data_structures::indexed_vec;
@@ -256,6 +256,14 @@ impl NodeId {
     pub fn as_u32(&self) -> u32 {
         self.0
     }
+
+    pub fn placeholder_from_mark(mark: Mark) -> Self {
+        NodeId(mark.as_u32())
+    }
+
+    pub fn placeholder_to_mark(self) -> Mark {
+        Mark::from_u32(self.0)
+    }
 }
 
 impl fmt::Display for NodeId {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6abeb4b0b2805..e258c51a3295f 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{self, Block, Ident, PatKind, Path};
+use ast::{self, Block, Ident, NodeId, PatKind, Path};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
@@ -321,7 +321,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
                 let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
-                placeholder_expander.add(mark.as_placeholder_id(), expansion, derives);
+                placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives);
             }
         }
 
@@ -703,7 +703,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 ..self.cx.current_expansion.clone()
             },
         });
-        placeholder(expansion_kind, mark.as_placeholder_id())
+        placeholder(expansion_kind, NodeId::placeholder_from_mark(mark))
     }
 
     fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion {
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index f0e328a551d5f..3075cdca862d1 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast;
+use ast::{self, NodeId};
 use codemap::{DUMMY_SP, dummy_spanned};
 use ext::base::ExtCtxt;
 use ext::expand::{Expansion, ExpansionKind};
@@ -88,7 +88,7 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
         let mut expansion = expansion.fold_with(self);
         if let Expansion::Items(mut items) = expansion {
             for derive in derives {
-                match self.remove(derive.as_placeholder_id()) {
+                match self.remove(NodeId::placeholder_from_mark(derive)) {
                     Expansion::Items(derived_items) => items.extend(derived_items),
                     _ => unreachable!(),
                 }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 4c9a5d512af02..6c975f3fc4021 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -136,12 +136,12 @@ pub mod print {
 }
 
 pub mod ext {
+    pub use syntax_pos::hygiene;
     pub mod base;
     pub mod build;
     pub mod derive;
     pub mod expand;
     pub mod placeholders;
-    pub mod hygiene;
     pub mod quote;
     pub mod source_util;
 
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax_pos/hygiene.rs
similarity index 95%
rename from src/libsyntax/ext/hygiene.rs
rename to src/libsyntax_pos/hygiene.rs
index 57f5ab73d3706..feebbcd6f03b6 100644
--- a/src/libsyntax/ext/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -15,7 +15,6 @@
 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
 //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
 
-use ast::NodeId;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
@@ -47,17 +46,13 @@ impl Mark {
         Mark(0)
     }
 
-    pub fn from_placeholder_id(id: NodeId) -> Self {
-        Mark(id.as_u32())
-    }
-
-    pub fn as_placeholder_id(self) -> NodeId {
-        NodeId::from_u32(self.0)
-    }
-
     pub fn as_u32(self) -> u32 {
         self.0
     }
+
+    pub fn from_u32(raw: u32) -> Mark {
+        Mark(raw)
+    }
 }
 
 struct HygieneData {
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 3808923e7728f..1c9a05dadd15f 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -23,6 +23,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![deny(warnings)]
 
+#![feature(const_fn)]
 #![feature(custom_attribute)]
 #![allow(unused_attributes)]
 #![feature(rustc_private)]
@@ -41,6 +42,8 @@ use serialize::{Encodable, Decodable, Encoder, Decoder};
 extern crate serialize;
 extern crate serialize as rustc_serialize; // used by deriving
 
+pub mod hygiene;
+
 pub type FileName = String;
 
 /// Spans represent a region of code, used for error reporting. Positions in spans

From 074a3c43749d9e58ee568519d61a958bbe4acb45 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Thu, 16 Mar 2017 10:31:36 +0000
Subject: [PATCH 08/14] Remove code in `syntax::codemap`.

---
 src/libsyntax/codemap.rs | 185 ---------------------------------------
 src/libsyntax_pos/lib.rs |   4 -
 2 files changed, 189 deletions(-)

diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 0f4b844b0eac8..388f3cb732351 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -409,101 +409,6 @@ impl CodeMap {
                         hi.col.to_usize() + 1)).to_string()
     }
 
-    // Returns true if two spans have the same callee
-    // (Assumes the same ExpnFormat implies same callee)
-    fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool {
-        let fmt_a = self
-            .with_expn_info(sp_a.expn_id,
-                            |ei| ei.map(|ei| ei.callee.format.clone()));
-
-        let fmt_b = self
-            .with_expn_info(sp_b.expn_id,
-                            |ei| ei.map(|ei| ei.callee.format.clone()));
-        fmt_a == fmt_b
-    }
-
-    /// Returns a formatted string showing the expansion chain of a span
-    ///
-    /// Spans are printed in the following format:
-    ///
-    /// filename:start_line:col: end_line:col
-    /// snippet
-    ///   Callee:
-    ///   Callee span
-    ///   Callsite:
-    ///   Callsite span
-    ///
-    /// Callees and callsites are printed recursively (if available, otherwise header
-    /// and span is omitted), expanding into their own callee/callsite spans.
-    /// Each layer of recursion has an increased indent, and snippets are truncated
-    /// to at most 50 characters. Finally, recursive calls to the same macro are squashed,
-    /// with '...' used to represent any number of recursive calls.
-    pub fn span_to_expanded_string(&self, sp: Span) -> String {
-        self.span_to_expanded_string_internal(sp, "")
-    }
-
-    fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String {
-        let mut indent = indent.to_owned();
-        let mut output = "".to_owned();
-        let span_str = self.span_to_string(sp);
-        let mut span_snip = self.span_to_snippet(sp)
-            .unwrap_or("Snippet unavailable".to_owned());
-
-        // Truncate by code points - in worst case this will be more than 50 characters,
-        // but ensures at least 50 characters and respects byte boundaries.
-        let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect();
-        if char_vec.len() > 50 {
-            span_snip.truncate(char_vec[49].0);
-            span_snip.push_str("...");
-        }
-
-        output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip));
-
-        if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN {
-            return output;
-        }
-
-        let mut callee = self.with_expn_info(sp.expn_id,
-                                             |ei| ei.and_then(|ei| ei.callee.span.clone()));
-        let mut callsite = self.with_expn_info(sp.expn_id,
-                                               |ei| ei.map(|ei| ei.call_site.clone()));
-
-        indent.push_str("  ");
-        let mut is_recursive = false;
-
-        while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) {
-            callee = self.with_expn_info(callee.unwrap().expn_id,
-                                         |ei| ei.and_then(|ei| ei.callee.span.clone()));
-            is_recursive = true;
-        }
-        if let Some(span) = callee {
-            output.push_str(&indent);
-            output.push_str("Callee:\n");
-            if is_recursive {
-                output.push_str(&indent);
-                output.push_str("...\n");
-            }
-            output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
-        }
-
-        is_recursive = false;
-        while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) {
-            callsite = self.with_expn_info(callsite.unwrap().expn_id,
-                                           |ei| ei.map(|ei| ei.call_site.clone()));
-            is_recursive = true;
-        }
-        if let Some(span) = callsite {
-            output.push_str(&indent);
-            output.push_str("Callsite:\n");
-            if is_recursive {
-                output.push_str(&indent);
-                output.push_str("...\n");
-            }
-            output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
-        }
-        output
-    }
-
     /// Return the source span - this is either the supplied span, or the span for
     /// the macro callsite that expanded to it.
     pub fn source_callsite(&self, sp: Span) -> Span {
@@ -1069,59 +974,6 @@ mod tests {
         assert_eq!(sstr, "blork.rs:2:1: 2:12");
     }
 
-    #[test]
-    fn t10() {
-        // Test span_to_expanded_string works in base case (no expansion)
-        let cm = init_code_map();
-        let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
-        let sstr = cm.span_to_expanded_string(span);
-        assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n");
-
-        let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION };
-        let sstr =  cm.span_to_expanded_string(span);
-        assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n");
-    }
-
-    #[test]
-    fn t11() {
-        // Test span_to_expanded_string works with expansion
-        let cm = init_code_map();
-        let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
-        let format = ExpnFormat::MacroBang(keywords::Invalid.name());
-        let callee = NameAndSpan { format: format,
-                                   allow_internal_unstable: false,
-                                   span: None };
-
-        let info = ExpnInfo { call_site: root, callee: callee };
-        let id = cm.record_expansion(info);
-        let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id };
-
-        let sstr = cm.span_to_expanded_string(sp);
-        assert_eq!(sstr,
-                   "blork.rs:2:1: 2:12\n`second line`\n  Callsite:\n  \
-                    blork.rs:1:1: 1:12\n  `first line.`\n");
-    }
-
-    /// Test merging two spans on the same line
-    #[test]
-    fn span_merging() {
-        let cm = CodeMap::new();
-        let inputtext  = "bbbb BB bb CCC\n";
-        let selection1 = "     ~~       \n";
-        let selection2 = "           ~~~\n";
-        cm.new_filemap_and_lines("blork.rs", None, inputtext);
-        let span1 = span_from_selection(inputtext, selection1);
-        let span2 = span_from_selection(inputtext, selection2);
-
-        if let Some(sp) = cm.merge_spans(span1, span2) {
-            let sstr = cm.span_to_expanded_string(sp);
-            assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
-        }
-        else {
-            assert!(false);
-        }
-    }
-
     /// Test failing to merge two spans on different lines
     #[test]
     fn span_merging_fail() {
@@ -1221,41 +1073,4 @@ mod tests {
         let id_end = cm.record_expansion(info_end);
         Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end }
     }
-
-    #[test]
-    fn t12() {
-        // Test span_to_expanded_string collapses recursive macros and handles
-        // recursive callsite and callee expansions
-        let cm = init_code_map();
-        let end = init_expansion_chain(&cm);
-        let sstr = cm.span_to_expanded_string(end);
-        let res_str =
-r"blork2.rs:2:1: 2:12
-`second line`
-  Callsite:
-  ...
-  blork2.rs:1:1: 1:12
-  `first line.`
-    Callee:
-    blork.rs:2:1: 2:12
-    `second line`
-      Callee:
-      blork.rs:1:1: 1:12
-      `first line.`
-      Callsite:
-      blork.rs:1:1: 1:12
-      `first line.`
-    Callsite:
-    ...
-    blork.rs:2:1: 2:12
-    `second line`
-      Callee:
-      blork.rs:1:1: 1:12
-      `first line.`
-      Callsite:
-      blork.rs:1:1: 1:12
-      `first line.`
-";
-        assert_eq!(sstr, res_str);
-    }
 }
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 1c9a05dadd15f..1b62d62348bc8 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -263,10 +263,6 @@ pub const NO_EXPANSION: ExpnId = ExpnId(!0);
 // For code appearing from the command line
 pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
 
-// For code generated by a procedural macro, without knowing which
-// Used in `qquote!`
-pub const PROC_EXPN: ExpnId = ExpnId(!2);
-
 impl ExpnId {
     pub fn from_u32(id: u32) -> ExpnId {
         ExpnId(id)

From da3ad474a792273500b965f24559a30897cd2662 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 17 Mar 2017 04:04:41 +0000
Subject: [PATCH 09/14] Merge `ExpnId` and `SyntaxContext`.

---
 src/librustc/hir/lowering.rs                  |   7 +-
 src/librustc/hir/mod.rs                       |   5 +-
 src/librustc/ich/caching_codemap_view.rs      |   4 -
 src/librustc/middle/region.rs                 |   2 +-
 src/librustc/middle/stability.rs              |   2 +-
 src/librustc_driver/driver.rs                 |   4 +-
 src/librustc_errors/emitter.rs                |  22 +-
 src/librustc_errors/lib.rs                    |   4 +-
 .../calculate_svh/svh_visitor.rs              |  17 +-
 src/librustc_mir/transform/qualify_consts.rs  |   4 +-
 src/librustc_plugin/load.rs                   |   4 +-
 src/librustc_save_analysis/lib.rs             |   7 +-
 src/librustc_save_analysis/span_utils.rs      |   3 +-
 src/librustc_trans/asm.rs                     |   4 +-
 src/librustc_trans/back/write.rs              |   6 +-
 src/librustc_trans/mir/mod.rs                 |  18 +-
 src/librustc_typeck/check/mod.rs              |   5 +-
 src/libsyntax/ast.rs                          |  57 +---
 src/libsyntax/codemap.rs                      | 291 +-----------------
 src/libsyntax/ext/base.rs                     |  74 ++---
 src/libsyntax/ext/derive.rs                   |  50 +--
 src/libsyntax/ext/expand.rs                   | 111 +++----
 src/libsyntax/ext/source_util.rs              |   2 +-
 src/libsyntax/ext/tt/quoted.rs                |  14 +-
 src/libsyntax/feature_gate.rs                 |  20 +-
 src/libsyntax/json.rs                         |   2 +-
 src/libsyntax/lib.rs                          |   2 +-
 src/libsyntax/parse/parser.rs                 |   6 +-
 src/libsyntax/std_inject.rs                   |  21 +-
 src/libsyntax/test.rs                         |  21 +-
 src/libsyntax/test_snippet.rs                 |   2 +-
 src/libsyntax/tokenstream.rs                  |  16 +-
 src/libsyntax_ext/asm.rs                      |  12 +-
 src/libsyntax_ext/deriving/clone.rs           |   2 +-
 src/libsyntax_ext/deriving/cmp/eq.rs          |   2 +-
 src/libsyntax_ext/deriving/debug.rs           |   4 +-
 src/libsyntax_ext/deriving/generic/mod.rs     |  12 +-
 src/libsyntax_ext/deriving/mod.rs             |  34 +-
 src/libsyntax_ext/proc_macro_registrar.rs     |   6 +-
 src/libsyntax_pos/hygiene.rs                  |  94 +++++-
 src/libsyntax_pos/lib.rs                      | 101 ++++--
 src/{libsyntax => libsyntax_pos}/symbol.rs    |  57 +++-
 src/test/compile-fail-fulldeps/qquote.rs      |   8 -
 src/test/run-fail-fulldeps/qquote.rs          |   8 -
 src/test/run-pass-fulldeps/qquote.rs          |   8 -
 45 files changed, 454 insertions(+), 701 deletions(-)
 rename src/{libsyntax => libsyntax_pos}/symbol.rs (86%)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 2ac1a036f99e1..60f019b384a0b 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -57,6 +57,7 @@ use std::mem;
 use syntax::attr;
 use syntax::ast::*;
 use syntax::errors;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ptr::P;
 use syntax::codemap::{self, respan, Spanned};
 use syntax::std_inject;
@@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span {
-        span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo {
+        let mark = Mark::fresh();
+        mark.set_expn_info(codemap::ExpnInfo {
             call_site: span,
             callee: codemap::NameAndSpan {
                 format: codemap::CompilerDesugaring(Symbol::intern(reason)),
@@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> {
                 allow_internal_unstable: true,
             },
         });
+        span.ctxt = SyntaxContext::empty().apply_mark(mark);
         span
     }
 
@@ -1998,7 +2001,7 @@ impl<'a> LoweringContext<'a> {
                     volatile: asm.volatile,
                     alignstack: asm.alignstack,
                     dialect: asm.dialect,
-                    expn_id: asm.expn_id,
+                    ctxt: asm.ctxt,
                 };
                 let outputs =
                     asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect();
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1c79a02d3da0e..51a591ece97a9 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -33,11 +33,12 @@ use hir::def::Def;
 use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
 use util::nodemap::{NodeMap, FxHashSet};
 
-use syntax_pos::{Span, ExpnId, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
 use syntax::codemap::{self, Spanned};
 use syntax::abi::Abi;
 use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
+use syntax::ext::hygiene::SyntaxContext;
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
 use syntax::tokenstream::TokenStream;
@@ -1363,7 +1364,7 @@ pub struct InlineAsm {
     pub volatile: bool,
     pub alignstack: bool,
     pub dialect: AsmDialect,
-    pub expn_id: ExpnId,
+    pub ctxt: SyntaxContext,
 }
 
 /// represents an argument in a function header
diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs
index a71251eedf5d0..1278d9f5171b3 100644
--- a/src/librustc/ich/caching_codemap_view.rs
+++ b/src/librustc/ich/caching_codemap_view.rs
@@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> {
         }
     }
 
-    pub fn codemap(&self) -> &'tcx CodeMap {
-        self.codemap
-    }
-
     pub fn byte_pos_to_line_and_col(&mut self,
                                     pos: BytePos)
                                     -> Option<(Rc<FileMap>, usize, BytePos)> {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index a19f15a9329fb..0676075930dc3 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -236,7 +236,7 @@ impl CodeExtent {
                         // (This is the special case aluded to in the
                         // doc-comment for this method)
                         let stmt_span = blk.stmts[r.first_statement_index as usize].span;
-                        Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id })
+                        Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt })
                     }
                 }
             }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 1fb5371402574..3dc6bd1ce8cb4 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -467,7 +467,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) {
-        if self.sess.codemap().span_allows_unstable(span) {
+        if span.allows_unstable() {
             debug!("stability: \
                     skipping span={:?} since it is internal", span);
             return;
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index d37553d7d660e..df8ae29bd0594 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -582,7 +582,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
     krate = time(time_passes, "crate injection", || {
         let alt_std_name = sess.opts.alt_std_name.clone();
-        syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name)
+        syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name)
     });
 
     let mut addl_plugins = Some(addl_plugins);
@@ -800,7 +800,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
     // Discard hygiene data, which isn't required after lowering to HIR.
     if !keep_hygiene_data(sess) {
-        syntax::ext::hygiene::reset_hygiene_data();
+        syntax::ext::hygiene::clear_markings();
     }
 
     Ok(ExpansionResult {
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 431edb3c9bc4d..367b85ac726db 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -10,7 +10,7 @@
 
 use self::Destination::*;
 
-use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
+use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
 
 use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
 use RenderSpan::*;
@@ -151,7 +151,7 @@ impl EmitterWriter {
 
         if let Some(ref cm) = self.cm {
             for span_label in msp.span_labels() {
-                if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP {
+                if span_label.span == DUMMY_SP {
                     continue;
                 }
                 let lo = cm.lookup_char_pos(span_label.span.lo);
@@ -615,7 +615,7 @@ impl EmitterWriter {
         let mut max = 0;
         if let Some(ref cm) = self.cm {
             for primary_span in msp.primary_spans() {
-                if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP {
+                if primary_span != &DUMMY_SP {
                     let hi = cm.lookup_char_pos(primary_span.hi);
                     if hi.line > max {
                         max = hi.line;
@@ -623,7 +623,7 @@ impl EmitterWriter {
                 }
             }
             for span_label in msp.span_labels() {
-                if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP {
+                if span_label.span != DUMMY_SP {
                     let hi = cm.lookup_char_pos(span_label.span.hi);
                     if hi.line > max {
                         max = hi.line;
@@ -659,20 +659,20 @@ impl EmitterWriter {
 
             // First, find all the spans in <*macros> and point instead at their use site
             for sp in span.primary_spans() {
-                if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) {
+                if *sp == DUMMY_SP {
                     continue;
                 }
                 if cm.span_to_filename(sp.clone()).contains("macros>") {
-                    let v = cm.macro_backtrace(sp.clone());
+                    let v = sp.macro_backtrace();
                     if let Some(use_site) = v.last() {
                         before_after.push((sp.clone(), use_site.call_site.clone()));
                     }
                 }
-                for trace in cm.macro_backtrace(sp.clone()).iter().rev() {
+                for trace in sp.macro_backtrace().iter().rev() {
                     // Only show macro locations that are local
                     // and display them like a span_note
                     if let Some(def_site) = trace.def_site_span {
-                        if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) {
+                        if def_site == DUMMY_SP {
                             continue;
                         }
                         // Check to make sure we're not in any <*macros>
@@ -689,11 +689,11 @@ impl EmitterWriter {
                 span.push_span_label(label_span, label_text);
             }
             for sp_label in span.span_labels() {
-                if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) {
+                if sp_label.span == DUMMY_SP {
                     continue;
                 }
                 if cm.span_to_filename(sp_label.span.clone()).contains("macros>") {
-                    let v = cm.macro_backtrace(sp_label.span.clone());
+                    let v = sp_label.span.macro_backtrace();
                     if let Some(use_site) = v.last() {
                         before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
                     }
@@ -848,7 +848,7 @@ impl EmitterWriter {
         // Make sure our primary file comes first
         let primary_lo = if let (Some(ref cm), Some(ref primary_span)) =
             (self.cm.as_ref(), msp.primary_span().as_ref()) {
-            if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP {
+            if primary_span != &&DUMMY_SP {
                 cm.lookup_char_pos(primary_span.lo)
             } else {
                 emit_to_destination(&buffer.render(), level, &mut self.dst)?;
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 4c889dad8ca50..2efdaa57fba36 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -48,7 +48,6 @@ pub mod styled_buffer;
 mod lock;
 
 use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION};
-use syntax_pos::MacroBacktrace;
 
 #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum RenderSpan {
@@ -75,7 +74,6 @@ pub trait CodeMapper {
     fn span_to_lines(&self, sp: Span) -> FileLinesResult;
     fn span_to_string(&self, sp: Span) -> String;
     fn span_to_filename(&self, sp: Span) -> FileName;
-    fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
 }
 
@@ -120,7 +118,7 @@ impl CodeSuggestion {
         let bounding_span = Span {
             lo: lo,
             hi: hi,
-            expn_id: NO_EXPANSION,
+            ctxt: NO_EXPANSION,
         };
         let lines = cm.span_to_lines(bounding_span).unwrap();
         assert!(!lines.lines.is_empty());
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 210803c3f329c..5401b371888e9 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -17,9 +17,10 @@ use self::SawTraitOrImplItemComponent::*;
 use syntax::abi::Abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
+use syntax::ext::hygiene::SyntaxContext;
 use syntax::parse::token;
 use syntax::symbol::InternedString;
-use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
+use syntax_pos::{Span, BytePos};
 use syntax::tokenstream;
 use rustc::hir;
 use rustc::hir::*;
@@ -92,10 +93,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             span.hi
         };
 
-        let expn_kind = match span.expn_id {
-            NO_EXPANSION => SawSpanExpnKind::NoExpansion,
-            COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine,
-            _ => SawSpanExpnKind::SomeExpansion,
+        let expn_kind = if span.ctxt == SyntaxContext::empty() {
+            SawSpanExpnKind::NoExpansion
+        } else {
+            SawSpanExpnKind::SomeExpansion
         };
 
         let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo);
@@ -121,8 +122,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
         saw.hash(self.st);
 
         if expn_kind == SawSpanExpnKind::SomeExpansion {
-            let call_site = self.codemap.codemap().source_callsite(span);
-            self.hash_span(call_site);
+            self.hash_span(span.source_callsite());
         }
     }
 
@@ -483,7 +483,6 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
 #[derive(Clone, Copy, Hash, Eq, PartialEq)]
 enum SawSpanExpnKind {
     NoExpansion,
-    CommandLine,
     SomeExpansion,
 }
 
@@ -501,7 +500,7 @@ impl<'a> Hash for StableInlineAsm<'a> {
             volatile,
             alignstack,
             dialect,
-            expn_id: _, // This is used for error reporting
+            ctxt: _, // This is used for error reporting
         } = *self.0;
 
         asm.as_str().hash(state);
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index e998665e03536..1f5005c171cb8 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -223,7 +223,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             }
 
             // This comes from a macro that has #[allow_internal_unstable].
-            if self.tcx.sess.codemap().span_allows_unstable(self.span) {
+            if self.span.allows_unstable() {
                 return;
             }
 
@@ -810,7 +810,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     self.def_id.is_local() &&
 
                     // this doesn't come from a macro that has #[allow_internal_unstable]
-                    !self.tcx.sess.codemap().span_allows_unstable(self.span)
+                    !self.span.allows_unstable()
                 {
                     let mut err = self.tcx.sess.struct_span_err(self.span,
                         "const fns are an unstable feature");
diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs
index 1bfc445fca98d..486f3936f2549 100644
--- a/src/librustc_plugin/load.rs
+++ b/src/librustc_plugin/load.rs
@@ -20,7 +20,7 @@ use std::env;
 use std::mem;
 use std::path::PathBuf;
 use syntax::ast;
-use syntax_pos::{Span, COMMAND_LINE_SP};
+use syntax_pos::{Span, DUMMY_SP};
 
 /// Pointer to a registrar function.
 pub type PluginRegistrarFun =
@@ -81,7 +81,7 @@ pub fn load_plugins(sess: &Session,
 
     if let Some(plugins) = addl_plugins {
         for plugin in plugins {
-            loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]);
+            loader.load_plugin(DUMMY_SP, &plugin, vec![]);
         }
     }
 
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 5e2b1df9d34f8..e2eee0a16006a 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -689,9 +689,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         // Note we take care to use the source callsite/callee, to handle
         // nested expansions and ensure we only generate data for source-visible
         // macro uses.
-        let callsite = self.tcx.sess.codemap().source_callsite(span);
-        let callee = self.tcx.sess.codemap().source_callee(span);
-        let callee = option_try!(callee);
+        let callsite = span.source_callsite();
+        let callee = option_try!(span.source_callee());
         let callee_span = option_try!(callee.span);
 
         // Ignore attribute macros, their spans are usually mangled
@@ -950,5 +949,5 @@ fn escape(s: String) -> String {
 // Helper function to determine if a span came from a
 // macro expansion or syntax extension.
 pub fn generated_code(span: Span) -> bool {
-    span.expn_id != NO_EXPANSION || span == DUMMY_SP
+    span.ctxt != NO_EXPANSION || span == DUMMY_SP
 }
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index 34402742e6c33..c19f805a28575 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -462,8 +462,7 @@ impl<'a> SpanUtils<'a> {
 
         // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
         // callsite. This filters out macro internal variables and most malformed spans.
-        let span = self.sess.codemap().source_callsite(parent);
-        !(span.contains(parent))
+        !parent.source_callsite().contains(parent)
     }
 }
 
diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs
index 12e4e57964f98..d0ee42f9c839a 100644
--- a/src/librustc_trans/asm.rs
+++ b/src/librustc_trans/asm.rs
@@ -111,14 +111,14 @@ pub fn trans_inline_asm<'a, 'tcx>(
         bcx.store(v, val, None);
     }
 
-    // Store expn_id in a metadata node so we can map LLVM errors
+    // Store mark in a metadata node so we can map LLVM errors
     // back to source locations.  See #17552.
     unsafe {
         let key = "srcloc";
         let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx.llcx(),
             key.as_ptr() as *const c_char, key.len() as c_uint);
 
-        let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32);
+        let val: llvm::ValueRef = C_i32(bcx.ccx, ia.ctxt.outer().as_u32() as i32);
 
         llvm::LLVMSetMetadata(r, kind,
             llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1));
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 377ff34cb7e0d..8fd8b66c28373 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -371,14 +371,14 @@ struct HandlerFreeVars<'a> {
 unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
                                                msg: &'b str,
                                                cookie: c_uint) {
-    use syntax_pos::ExpnId;
+    use syntax::ext::hygiene::Mark;
 
     match cgcx.lto_ctxt {
         Some((sess, _)) => {
-            sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info {
+            match Mark::from_u32(cookie).expn_info() {
                 Some(ei) => sess.span_err(ei.call_site, msg),
                 None     => sess.err(msg),
-            });
+            };
         }
 
         None => {
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 6419f41f86b6d..21bbbea77d442 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -26,7 +26,7 @@ use monomorphize::{self, Instance};
 use abi::FnType;
 use type_of;
 
-use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
+use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
 use syntax::symbol::keywords;
 
 use std::iter;
@@ -124,24 +124,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         // In order to have a good line stepping behavior in debugger, we overwrite debug
         // locations of macro expansions with that of the outermost expansion site
         // (unless the crate is being compiled with `-Z debug-macros`).
-        if source_info.span.expn_id == NO_EXPANSION ||
-            source_info.span.expn_id == COMMAND_LINE_EXPN ||
-            self.ccx.sess().opts.debugging_opts.debug_macros {
-
+        if source_info.span.ctxt == NO_EXPANSION ||
+           self.ccx.sess().opts.debugging_opts.debug_macros {
             let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo);
             (scope, source_info.span)
         } else {
-            let cm = self.ccx.sess().codemap();
             // Walk up the macro expansion chain until we reach a non-expanded span.
             // We also stop at the function body level because no line stepping can occurr
             // at the level above that.
             let mut span = source_info.span;
-            while span.expn_id != NO_EXPANSION &&
-                  span.expn_id != COMMAND_LINE_EXPN &&
-                  span.expn_id != self.mir.span.expn_id {
-                if let Some(callsite_span) = cm.with_expn_info(span.expn_id,
-                                                    |ei| ei.map(|ei| ei.call_site.clone())) {
-                    span = callsite_span;
+            while span.ctxt != NO_EXPANSION && span.ctxt != self.mir.span.ctxt {
+                if let Some(info) = span.ctxt.outer().expn_info() {
+                    span = info.call_site;
                 } else {
                     break;
                 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c857388106d5a..eb0b3e8c3e0ac 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4150,12 +4150,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
                 if let Some(last_stmt) = extra_semi {
-                    let original_span = original_sp(self.tcx.sess.codemap(),
-                                                    last_stmt.span, blk.span);
+                    let original_span = original_sp(last_stmt.span, blk.span);
                     let span_semi = Span {
                         lo: original_span.hi - BytePos(1),
                         hi: original_span.hi,
-                        expn_id: original_span.expn_id
+                        ctxt: original_span.ctxt,
                     };
                     err.span_help(span_semi, "consider removing this semicolon:");
                 }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 7e2b225193f6d..a4bebd311ded2 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -14,10 +14,10 @@ pub use self::TyParamBound::*;
 pub use self::UnsafeSource::*;
 pub use self::ViewPath_::*;
 pub use self::PathParameters::*;
-pub use symbol::Symbol as Name;
+pub use symbol::{Ident, Symbol as Name};
 pub use util::ThinVec;
 
-use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId};
+use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP};
 use codemap::{respan, Spanned};
 use abi::Abi;
 use ext::hygiene::{Mark, SyntaxContext};
@@ -27,61 +27,12 @@ use rustc_data_structures::indexed_vec;
 use symbol::{Symbol, keywords};
 use tokenstream::{ThinTokenStream, TokenStream};
 
+use serialize::{self, Encoder, Decoder};
 use std::collections::HashSet;
 use std::fmt;
 use std::rc::Rc;
 use std::u32;
 
-use serialize::{self, Encodable, Decodable, Encoder, Decoder};
-
-/// An identifier contains a Name (index into the interner
-/// table) and a SyntaxContext to track renaming and
-/// macro expansion per Flatt et al., "Macros That Work Together"
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Ident {
-    pub name: Symbol,
-    pub ctxt: SyntaxContext
-}
-
-impl Ident {
-    pub const fn with_empty_ctxt(name: Name) -> Ident {
-        Ident { name: name, ctxt: SyntaxContext::empty() }
-    }
-
-    /// Maps a string to an identifier with an empty syntax context.
-    pub fn from_str(s: &str) -> Ident {
-        Ident::with_empty_ctxt(Symbol::intern(s))
-    }
-
-    pub fn unhygienize(&self) -> Ident {
-        Ident { name: self.name, ctxt: SyntaxContext::empty() }
-    }
-}
-
-impl fmt::Debug for Ident {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}{:?}", self.name, self.ctxt)
-    }
-}
-
-impl fmt::Display for Ident {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&self.name, f)
-    }
-}
-
-impl Encodable for Ident {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        self.name.encode(s)
-    }
-}
-
-impl Decodable for Ident {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
-        Ok(Ident::with_empty_ctxt(Name::decode(d)?))
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
@@ -1445,7 +1396,7 @@ pub struct InlineAsm {
     pub volatile: bool,
     pub alignstack: bool,
     pub dialect: AsmDialect,
-    pub expn_id: ExpnId,
+    pub ctxt: SyntaxContext,
 }
 
 /// An argument in a function header.
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 388f3cb732351..ba199eacb6276 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -17,6 +17,8 @@
 //! within the CodeMap, which upon request can be converted to line and column
 //! information, source code snippets, etc.
 
+pub use syntax_pos::*;
+pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan};
 pub use self::ExpnFormat::*;
 
 use std::cell::RefCell;
@@ -26,35 +28,21 @@ use std::rc::Rc;
 use std::env;
 use std::fs;
 use std::io::{self, Read};
-pub use syntax_pos::*;
 use errors::CodeMapper;
 
-use ast::Name;
-
 /// Return the span itself if it doesn't come from a macro expansion,
 /// otherwise return the call site span up to the `enclosing_sp` by
 /// following the `expn_info` chain.
-pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span {
-    let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site));
-    let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site));
+pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
+    let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site);
+    let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site);
     match (call_site1, call_site2) {
         (None, _) => sp,
         (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp,
-        (Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp),
+        (Some(call_site1), _) => original_sp(call_site1, enclosing_sp),
     }
 }
 
-/// The source of expansion.
-#[derive(Clone, Hash, Debug, PartialEq, Eq)]
-pub enum ExpnFormat {
-    /// e.g. #[derive(...)] <item>
-    MacroAttribute(Name),
-    /// e.g. `format!()`
-    MacroBang(Name),
-    /// Desugaring done by the compiler during HIR lowering.
-    CompilerDesugaring(Name)
-}
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub struct Spanned<T> {
     pub node: T,
@@ -73,47 +61,6 @@ pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
     respan(DUMMY_SP, t)
 }
 
-#[derive(Clone, Hash, Debug)]
-pub struct NameAndSpan {
-    /// The format with which the macro was invoked.
-    pub format: ExpnFormat,
-    /// Whether the macro is allowed to use #[unstable]/feature-gated
-    /// features internally without forcing the whole crate to opt-in
-    /// to them.
-    pub allow_internal_unstable: bool,
-    /// The span of the macro definition itself. The macro may not
-    /// have a sensible definition span (e.g. something defined
-    /// completely inside libsyntax) in which case this is None.
-    pub span: Option<Span>
-}
-
-impl NameAndSpan {
-    pub fn name(&self) -> Name {
-        match self.format {
-            ExpnFormat::MacroAttribute(s) |
-            ExpnFormat::MacroBang(s) |
-            ExpnFormat::CompilerDesugaring(s) => s,
-        }
-    }
-}
-
-/// Extra information for tracking spans of macro and syntax sugar expansion
-#[derive(Hash, Debug)]
-pub struct ExpnInfo {
-    /// The location of the actual macro invocation or syntax sugar , e.g.
-    /// `let x = foo!();` or `if let Some(y) = x {}`
-    ///
-    /// This may recursively refer to other macro invocations, e.g. if
-    /// `foo!()` invoked `bar!()` internally, and there was an
-    /// expression inside `bar!`; the call_site of the expression in
-    /// the expansion would point to the `bar!` invocation; that
-    /// call_site span would have its own ExpnInfo, with the call_site
-    /// pointing to the `foo!` invocation.
-    pub call_site: Span,
-    /// Information about the expansion.
-    pub callee: NameAndSpan
-}
-
 // _____________________________________________________________________________
 // FileMap, MultiByteChar, FileName, FileLines
 //
@@ -161,7 +108,6 @@ impl FileLoader for RealFileLoader {
 
 pub struct CodeMap {
     pub files: RefCell<Vec<Rc<FileMap>>>,
-    expansions: RefCell<Vec<ExpnInfo>>,
     file_loader: Box<FileLoader>
 }
 
@@ -169,7 +115,6 @@ impl CodeMap {
     pub fn new() -> CodeMap {
         CodeMap {
             files: RefCell::new(Vec::new()),
-            expansions: RefCell::new(Vec::new()),
             file_loader: Box::new(RealFileLoader)
         }
     }
@@ -177,7 +122,6 @@ impl CodeMap {
     pub fn with_file_loader(file_loader: Box<FileLoader>) -> CodeMap {
         CodeMap {
             files: RefCell::new(Vec::new()),
-            expansions: RefCell::new(Vec::new()),
             file_loader: file_loader
         }
     }
@@ -353,14 +297,14 @@ impl CodeMap {
     /// Returns `Some(span)`, a union of the lhs and rhs span.  The lhs must precede the rhs. If
     /// there are gaps between lhs and rhs, the resulting union will cross these gaps.
     /// For this to work, the spans have to be:
-    ///    * the expn_id of both spans much match
+    ///    * the ctxt of both spans much match
     ///    * the lhs span needs to end on the same line the rhs span begins
     ///    * the lhs span must start at or before the rhs span
     pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
         use std::cmp;
 
         // make sure we're at the same expansion id
-        if sp_lhs.expn_id != sp_rhs.expn_id {
+        if sp_lhs.ctxt != sp_rhs.ctxt {
             return None;
         }
 
@@ -383,7 +327,7 @@ impl CodeMap {
             Some(Span {
                 lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
                 hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
-                expn_id: sp_lhs.expn_id,
+                ctxt: sp_lhs.ctxt,
             })
         } else {
             None
@@ -391,10 +335,6 @@ impl CodeMap {
     }
 
     pub fn span_to_string(&self, sp: Span) -> String {
-        if sp == COMMAND_LINE_SP {
-            return "<command line option>".to_string();
-        }
-
         if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) {
             return "no-location".to_string();
         }
@@ -409,62 +349,6 @@ impl CodeMap {
                         hi.col.to_usize() + 1)).to_string()
     }
 
-    /// Return the source span - this is either the supplied span, or the span for
-    /// the macro callsite that expanded to it.
-    pub fn source_callsite(&self, sp: Span) -> Span {
-        let mut span = sp;
-        // Special case - if a macro is parsed as an argument to another macro, the source
-        // callsite is the first callsite, which is also source-equivalent to the span.
-        let mut first = true;
-        while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
-            if let Some(callsite) = self.with_expn_info(span.expn_id,
-                                               |ei| ei.map(|ei| ei.call_site.clone())) {
-                if first && span.source_equal(&callsite) {
-                    if self.lookup_char_pos(span.lo).file.is_real_file() {
-                        return Span { expn_id: NO_EXPANSION, .. span };
-                    }
-                }
-                first = false;
-                span = callsite;
-            }
-            else {
-                break;
-            }
-        }
-        span
-    }
-
-    /// Return the source callee.
-    ///
-    /// Returns None if the supplied span has no expansion trace,
-    /// else returns the NameAndSpan for the macro definition
-    /// corresponding to the source callsite.
-    pub fn source_callee(&self, sp: Span) -> Option<NameAndSpan> {
-        let mut span = sp;
-        // Special case - if a macro is parsed as an argument to another macro, the source
-        // callsite is source-equivalent to the span, and the source callee is the first callee.
-        let mut first = true;
-        while let Some(callsite) = self.with_expn_info(span.expn_id,
-                                            |ei| ei.map(|ei| ei.call_site.clone())) {
-            if first && span.source_equal(&callsite) {
-                if self.lookup_char_pos(span.lo).file.is_real_file() {
-                    return self.with_expn_info(span.expn_id,
-                                               |ei| ei.map(|ei| ei.callee.clone()));
-                }
-            }
-            first = false;
-            if let Some(_) = self.with_expn_info(callsite.expn_id,
-                                                 |ei| ei.map(|ei| ei.call_site.clone())) {
-                span = callsite;
-            }
-            else {
-                return self.with_expn_info(span.expn_id,
-                                           |ei| ei.map(|ei| ei.callee.clone()));
-            }
-        }
-        None
-    }
-
     pub fn span_to_filename(&self, sp: Span) -> FileName {
         self.lookup_char_pos(sp.lo).file.name.to_string()
     }
@@ -628,111 +512,9 @@ impl CodeMap {
         return a;
     }
 
-    pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
-        let mut expansions = self.expansions.borrow_mut();
-        expansions.push(expn_info);
-        let len = expansions.len();
-        if len > u32::max_value() as usize {
-            panic!("too many ExpnInfo's!");
-        }
-        ExpnId(len as u32 - 1)
-    }
-
-    pub fn with_expn_info<T, F>(&self, id: ExpnId, f: F) -> T where
-        F: FnOnce(Option<&ExpnInfo>) -> T,
-    {
-        match id {
-            NO_EXPANSION | COMMAND_LINE_EXPN => f(None),
-            ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize]))
-        }
-    }
-
-    /// Check if a span is "internal" to a macro in which #[unstable]
-    /// items can be used (that is, a macro marked with
-    /// `#[allow_internal_unstable]`).
-    pub fn span_allows_unstable(&self, span: Span) -> bool {
-        debug!("span_allows_unstable(span = {:?})", span);
-        let mut allows_unstable = false;
-        let mut expn_id = span.expn_id;
-        loop {
-            let quit = self.with_expn_info(expn_id, |expninfo| {
-                debug!("span_allows_unstable: expninfo = {:?}", expninfo);
-                expninfo.map_or(/* hit the top level */ true, |info| {
-
-                    let span_comes_from_this_expansion =
-                        info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| {
-                            mac_span.contains(span)
-                        });
-
-                    debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}",
-                           (span.lo, span.hi),
-                           (info.call_site.lo, info.call_site.hi),
-                           info.callee.span.map(|x| (x.lo, x.hi)));
-                    debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}",
-                           span_comes_from_this_expansion,
-                           info.callee.allow_internal_unstable);
-                    if span_comes_from_this_expansion {
-                        allows_unstable = info.callee.allow_internal_unstable;
-                        // we've found the right place, stop looking
-                        true
-                    } else {
-                        // not the right place, keep looking
-                        expn_id = info.call_site.expn_id;
-                        false
-                    }
-                })
-            });
-            if quit {
-                break
-            }
-        }
-        debug!("span_allows_unstable? {}", allows_unstable);
-        allows_unstable
-    }
-
     pub fn count_lines(&self) -> usize {
         self.files.borrow().iter().fold(0, |a, f| a + f.count_lines())
     }
-
-    pub fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
-        let mut prev_span = DUMMY_SP;
-        let mut span = span;
-        let mut result = vec![];
-        loop {
-            let span_name_span = self.with_expn_info(span.expn_id, |expn_info| {
-                expn_info.map(|ei| {
-                    let (pre, post) = match ei.callee.format {
-                        MacroAttribute(..) => ("#[", "]"),
-                        MacroBang(..) => ("", "!"),
-                        CompilerDesugaring(..) => ("desugaring of `", "`"),
-                    };
-                    let macro_decl_name = format!("{}{}{}",
-                                                  pre,
-                                                  ei.callee.name(),
-                                                  post);
-                    let def_site_span = ei.callee.span;
-                    (ei.call_site, macro_decl_name, def_site_span)
-                })
-            });
-
-            match span_name_span {
-                None => break,
-                Some((call_site, macro_decl_name, def_site_span)) => {
-                    // Don't print recursive invocations
-                    if !call_site.source_equal(&prev_span) {
-                        result.push(MacroBacktrace {
-                            call_site: call_site,
-                            macro_decl_name: macro_decl_name,
-                            def_site_span: def_site_span,
-                        });
-                    }
-                    prev_span = span;
-                    span = call_site;
-                }
-            }
-        }
-        result
-    }
 }
 
 impl CodeMapper for CodeMap {
@@ -748,9 +530,6 @@ impl CodeMapper for CodeMap {
     fn span_to_filename(&self, sp: Span) -> FileName {
         self.span_to_filename(sp)
     }
-    fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
-        self.macro_backtrace(span)
-    }
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
         self.merge_spans(sp_lhs, sp_rhs)
     }
@@ -763,7 +542,6 @@ impl CodeMapper for CodeMap {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use symbol::keywords;
     use std::rc::Rc;
 
     #[test]
@@ -912,7 +690,7 @@ mod tests {
     fn t7() {
         // Test span_to_lines for a span ending at the end of filemap
         let cm = init_code_map();
-        let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
+        let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
         let file_lines = cm.span_to_lines(span).unwrap();
 
         assert_eq!(file_lines.file.name, "blork.rs");
@@ -928,7 +706,7 @@ mod tests {
         assert_eq!(input.len(), selection.len());
         let left_index = selection.find('~').unwrap() as u32;
         let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
-        Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
+        Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION }
     }
 
     /// Test span_to_snippet and span_to_lines for a span coverting 3
@@ -958,7 +736,7 @@ mod tests {
     fn t8() {
         // Test span_to_snippet for a span ending at the end of filemap
         let cm = init_code_map();
-        let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
+        let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
         let snippet = cm.span_to_snippet(span);
 
         assert_eq!(snippet, Ok("second line".to_string()));
@@ -968,7 +746,7 @@ mod tests {
     fn t9() {
         // Test span_to_str for a span ending at the end of filemap
         let cm = init_code_map();
-        let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
+        let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
         let sstr =  cm.span_to_string(span);
 
         assert_eq!(sstr, "blork.rs:2:1: 2:12");
@@ -1022,7 +800,7 @@ mod tests {
                     let span = Span {
                         lo: BytePos(lo as u32 + file.start_pos.0),
                         hi: BytePos(hi as u32 + file.start_pos.0),
-                        expn_id: NO_EXPANSION,
+                        ctxt: NO_EXPANSION,
                     };
                     assert_eq!(&self.span_to_snippet(span).unwrap()[..],
                             substring);
@@ -1032,45 +810,4 @@ mod tests {
             }
         }
     }
-
-    fn init_expansion_chain(cm: &CodeMap) -> Span {
-        // Creates an expansion chain containing two recursive calls
-        // root -> expA -> expA -> expB -> expB -> end
-        let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
-
-        let format_root = ExpnFormat::MacroBang(keywords::Invalid.name());
-        let callee_root = NameAndSpan { format: format_root,
-                                        allow_internal_unstable: false,
-                                        span: Some(root) };
-
-        let info_a1 = ExpnInfo { call_site: root, callee: callee_root };
-        let id_a1 = cm.record_expansion(info_a1);
-        let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 };
-
-        let format_a = ExpnFormat::MacroBang(keywords::As.name());
-        let callee_a = NameAndSpan { format: format_a,
-                                      allow_internal_unstable: false,
-                                      span: Some(span_a1) };
-
-        let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() };
-        let id_a2 = cm.record_expansion(info_a2);
-        let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 };
-
-        let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a };
-        let id_b1 = cm.record_expansion(info_b1);
-        let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 };
-
-        let format_b = ExpnFormat::MacroBang(keywords::Box.name());
-        let callee_b = NameAndSpan { format: format_b,
-                                     allow_internal_unstable: false,
-                                     span: None };
-
-        let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() };
-        let id_b2 = cm.record_expansion(info_b2);
-        let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 };
-
-        let info_end = ExpnInfo { call_site: span_b2, callee: callee_b };
-        let id_end = cm.record_expansion(info_end);
-        Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end }
-    }
 }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index dc7e7673eb03c..a2d54b62ec65d 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT
 
 use ast::{self, Attribute, Name, PatKind, MetaItem};
 use attr::HasAttrs;
-use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
-use syntax_pos::{Span, ExpnId, NO_EXPANSION};
-use errors::{DiagnosticBuilder, FatalError};
+use codemap::{self, CodeMap, Spanned, respan};
+use syntax_pos::{Span, DUMMY_SP};
+use errors::DiagnosticBuilder;
 use ext::expand::{self, Expansion, Invocation};
-use ext::hygiene::Mark;
+use ext::hygiene::{Mark, SyntaxContext};
 use fold::{self, Folder};
 use parse::{self, parser, DirectoryOwnership};
 use parse::token;
@@ -56,6 +56,14 @@ impl HasAttrs for Annotatable {
 }
 
 impl Annotatable {
+    pub fn span(&self) -> Span {
+        match *self {
+            Annotatable::Item(ref item) => item.span,
+            Annotatable::TraitItem(ref trait_item) => trait_item.span,
+            Annotatable::ImplItem(ref impl_item) => impl_item.span,
+        }
+    }
+
     pub fn expect_item(self) -> P<ast::Item> {
         match self {
             Annotatable::Item(i) => i,
@@ -602,7 +610,6 @@ pub struct ModuleData {
 pub struct ExpansionData {
     pub mark: Mark,
     pub depth: usize,
-    pub backtrace: ExpnId,
     pub module: Rc<ModuleData>,
     pub directory_ownership: DirectoryOwnership,
 }
@@ -633,7 +640,6 @@ impl<'a> ExtCtxt<'a> {
             current_expansion: ExpansionData {
                 mark: Mark::root(),
                 depth: 0,
-                backtrace: NO_EXPANSION,
                 module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
                 directory_ownership: DirectoryOwnership::Owned,
             },
@@ -658,30 +664,30 @@ impl<'a> ExtCtxt<'a> {
     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
     pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config }
     pub fn call_site(&self) -> Span {
-        self.codemap().with_expn_info(self.backtrace(), |ei| match ei {
+        match self.current_expansion.mark.expn_info() {
             Some(expn_info) => expn_info.call_site,
-            None => self.bug("missing top span")
-        })
+            None => DUMMY_SP,
+        }
+    }
+    pub fn backtrace(&self) -> SyntaxContext {
+        SyntaxContext::empty().apply_mark(self.current_expansion.mark)
     }
-    pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace }
 
     /// Returns span for the macro which originally caused the current expansion to happen.
     ///
     /// Stops backtracing at include! boundary.
     pub fn expansion_cause(&self) -> Span {
-        let mut expn_id = self.backtrace();
+        let mut ctxt = self.backtrace();
         let mut last_macro = None;
         loop {
-            if self.codemap().with_expn_info(expn_id, |info| {
-                info.map_or(None, |i| {
-                    if i.callee.name() == "include" {
-                        // Stop going up the backtrace once include! is encountered
-                        return None;
-                    }
-                    expn_id = i.call_site.expn_id;
-                    last_macro = Some(i.call_site);
-                    return Some(());
-                })
+            if ctxt.outer().expn_info().map_or(None, |info| {
+                if info.callee.name() == "include" {
+                    // Stop going up the backtrace once include! is encountered
+                    return None;
+                }
+                ctxt = info.call_site.ctxt;
+                last_macro = Some(info.call_site);
+                return Some(());
             }).is_none() {
                 break
             }
@@ -689,28 +695,6 @@ impl<'a> ExtCtxt<'a> {
         last_macro.expect("missing expansion backtrace")
     }
 
-    pub fn bt_push(&mut self, ei: ExpnInfo) {
-        if self.current_expansion.depth > self.ecfg.recursion_limit {
-            let suggested_limit = self.ecfg.recursion_limit * 2;
-            let mut err = self.struct_span_fatal(ei.call_site,
-                &format!("recursion limit reached while expanding the macro `{}`",
-                         ei.callee.name()));
-            err.help(&format!(
-                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
-                suggested_limit));
-            err.emit();
-            panic!(FatalError);
-        }
-
-        let mut call_site = ei.call_site;
-        call_site.expn_id = self.backtrace();
-        self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo {
-            call_site: call_site,
-            callee: ei.callee
-        });
-    }
-    pub fn bt_pop(&mut self) {}
-
     pub fn struct_span_warn(&self,
                             sp: Span,
                             msg: &str)
@@ -792,9 +776,9 @@ impl<'a> ExtCtxt<'a> {
 /// compilation on error, merely emits a non-fatal error and returns None.
 pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str)
                               -> Option<Spanned<(Symbol, ast::StrStyle)>> {
-    // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
+    // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation.
     let expr = expr.map(|mut expr| {
-        expr.span.expn_id = cx.backtrace();
+        expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark);
         expr
     });
 
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 1569d9f540b8e..c79040424f619 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -9,13 +9,16 @@
 // except according to those terms.
 
 use attr::HasAttrs;
-use {ast, codemap};
+use ast;
+use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use parse::parser::PathStyle;
 use symbol::Symbol;
 use syntax_pos::Span;
 
+use std::collections::HashSet;
+
 pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
     let mut result = Vec::new();
     attrs.retain(|attr| {
@@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
     result
 }
 
-fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
-    Span {
-        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
-            call_site: span,
-            callee: codemap::NameAndSpan {
-                format: codemap::MacroAttribute(Symbol::intern(attr_name)),
-                span: Some(span),
-                allow_internal_unstable: true,
-            },
-        }),
-        ..span
+pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
+    where T: HasAttrs,
+{
+    let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned());
+    for (i, path) in traits.iter().enumerate() {
+        if i > 0 {
+            pretty_name.push_str(", ");
+        }
+        pretty_name.push_str(&path.to_string());
+        names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name);
     }
-}
+    pretty_name.push(')');
 
-pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T {
-    let span = match traits.get(0) {
-        Some(path) => path.span,
-        None => return item,
-    };
+    cx.current_expansion.mark.set_expn_info(ExpnInfo {
+        call_site: span,
+        callee: NameAndSpan {
+            format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
+            span: None,
+            allow_internal_unstable: true,
+        },
+    });
 
+    let span = Span { ctxt: cx.backtrace(), ..span };
     item.map_attrs(|mut attrs| {
-        if traits.iter().any(|path| *path == "PartialEq") &&
-           traits.iter().any(|path| *path == "Eq") {
-            let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
+        if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
             attrs.push(cx.attribute(span, meta));
         }
-        if traits.iter().any(|path| *path == "Copy") &&
-           traits.iter().any(|path| *path == "Clone") {
-            let span = allow_unstable(cx, span, "derive(Copy, Clone)");
+        if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) {
             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
             attrs.push(cx.attribute(span, meta));
         }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e258c51a3295f..1b3352f73ade7 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -13,6 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use config::{is_test_or_bench, StripUnconfigured};
+use errors::FatalError;
 use ext::base::*;
 use ext::derive::{add_derived_markers, collect_derives};
 use ext::hygiene::Mark;
@@ -27,7 +28,7 @@ use ptr::P;
 use std_inject;
 use symbol::Symbol;
 use symbol::keywords;
-use syntax_pos::{Span, ExpnId, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
 use tokenstream::TokenStream;
 use util::small_vector::SmallVector;
 use visit::Visitor;
@@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     let item = item
                         .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
                     let item_with_markers =
-                        add_derived_markers(&mut self.cx, &traits, item.clone());
+                        add_derived_markers(&mut self.cx, item.span(), &traits, item.clone());
                     let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
 
                     for path in &traits {
@@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 
     fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
-        match invoc.kind {
+        let result = match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
             InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
             InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
+        };
+
+        if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
+            let info = self.cx.current_expansion.mark.expn_info().unwrap();
+            let suggested_limit = self.cx.ecfg.recursion_limit * 2;
+            let mut err = self.cx.struct_span_fatal(info.call_site,
+                &format!("recursion limit reached while expanding the macro `{}`",
+                         info.callee.name()));
+            err.help(&format!(
+                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                suggested_limit));
+            err.emit();
+            panic!(FatalError);
         }
+
+        result
     }
 
     fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
@@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
 
         attr::mark_used(&attr);
-        self.cx.bt_push(ExpnInfo {
+        invoc.expansion_data.mark.set_expn_info(ExpnInfo {
             call_site: attr.span,
             callee: NameAndSpan {
                 format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
-                span: Some(attr.span),
+                span: None,
                 allow_internal_unstable: false,
             }
         });
@@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             SyntaxExtension::AttrProcMacro(ref mac) => {
                 let item_toks = stream_for_item(&item, &self.cx.parse_sess);
 
-                let span = Span {
-                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
-                        call_site: attr.span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
-                            span: None,
-                            allow_internal_unstable: false,
-                        },
-                    }),
-                    ..attr.span
-                };
-
-                let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks);
+                let span = Span { ctxt: self.cx.backtrace(), ..attr.span };
+                let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks);
                 self.parse_expansion(tok_result, kind, &attr.path, span)
             }
             SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
@@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let path = &mac.node.path;
 
         let ident = ident.unwrap_or(keywords::Invalid.ident());
-        let marked_tts =
-            noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
+        let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
         let opt_expanded = match *ext {
             NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                 if ident.name != keywords::Invalid.name() {
@@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     return kind.dummy(span);
                 }
 
-                self.cx.bt_push(ExpnInfo {
+                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(Symbol::intern(&format!("{}", path))),
@@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     return kind.dummy(span);
                 };
 
-                self.cx.bt_push(ExpnInfo {
+                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(Symbol::intern(&format!("{}", path))),
@@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     return kind.dummy(span);
                 }
 
-                self.cx.bt_push(ExpnInfo {
+                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(Symbol::intern(&format!("{}", path))),
@@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return kind.dummy(span);
         };
 
-        expanded.fold_with(&mut Marker {
-            mark: mark,
-            expn_id: Some(self.cx.backtrace()),
-        })
+        expanded.fold_with(&mut Marker(mark))
     }
 
     /// Expand a derive invocation. Returns the result of expansion.
@@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
         };
 
-        self.cx.bt_push(ExpnInfo {
+        let mut expn_info = ExpnInfo {
             call_site: span,
             callee: NameAndSpan {
                 format: MacroAttribute(pretty_name),
                 span: None,
                 allow_internal_unstable: false,
             }
-        });
+        };
 
         match *ext {
             SyntaxExtension::ProcMacroDerive(ref ext, _) => {
-                let span = Span {
-                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
-                        call_site: span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(pretty_name),
-                            span: None,
-                            allow_internal_unstable: false,
-                        },
-                    }),
-                    ..span
-                };
+                invoc.expansion_data.mark.set_expn_info(expn_info);
+                let span = Span { ctxt: self.cx.backtrace(), ..span };
                 let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
                     name: keywords::Invalid.name(),
                     span: DUMMY_SP,
                     node: ast::MetaItemKind::Word,
                 };
-                return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item));
+                kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item))
             }
             SyntaxExtension::BuiltinDerive(func) => {
-                let span = Span {
-                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
-                        call_site: span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(pretty_name),
-                            span: None,
-                            allow_internal_unstable: true,
-                        },
-                    }),
-                    ..span
-                };
+                expn_info.callee.allow_internal_unstable = true;
+                invoc.expansion_data.mark.set_expn_info(expn_info);
+                let span = Span { ctxt: self.cx.backtrace(), ..span };
                 let mut items = Vec::new();
                 func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a));
-                return kind.expect_from_annotatables(items);
+                kind.expect_from_annotatables(items)
             }
             _ => {
                 let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
@@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
-        let codemap = &self.cx.parse_sess.codemap();
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features);
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess, features);
         }
     }
 }
@@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> {
     }
 }
 
-// A Marker adds the given mark to the syntax context and
-// sets spans' `expn_id` to the given expn_id (unless it is `None`).
-struct Marker { mark: Mark, expn_id: Option<ExpnId> }
+// A Marker adds the given mark to the syntax context.
+struct Marker(Mark);
 
 impl Folder for Marker {
     fn fold_ident(&mut self, mut ident: Ident) -> Ident {
-        ident.ctxt = ident.ctxt.apply_mark(self.mark);
+        ident.ctxt = ident.ctxt.apply_mark(self.0);
         ident
     }
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        noop_fold_mac(mac, self)
-    }
 
     fn new_span(&mut self, mut span: Span) -> Span {
-        if let Some(expn_id) = self.expn_id {
-            span.expn_id = expn_id;
-        }
+        span.ctxt = span.ctxt.apply_mark(self.0);
         span
     }
+
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+        noop_fold_mac(mac, self)
+    }
 }
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 39b92c7d007de..0103d6ea959dd 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
 fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
     // NB: relative paths are resolved relative to the compilation unit
     if !arg.is_absolute() {
-        let callsite = cx.codemap().source_callsite(sp);
+        let callsite = sp.source_callsite();
         let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite));
         cu.pop();
         cu.push(arg);
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index d56859d805c87..12e746e024d3b 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -34,17 +34,19 @@ impl Delimited {
     }
 
     pub fn open_tt(&self, span: Span) -> TokenTree {
-        let open_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
+        let open_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(open_span, self.open_token())
     }
 
     pub fn close_tt(&self, span: Span) -> TokenTree {
-        let close_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
+        let close_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(close_span, self.close_token())
     }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 7af432176cf6e..70111396a4b92 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -28,7 +28,7 @@ use self::AttributeGate::*;
 use abi::Abi;
 use ast::{self, NodeId, PatKind, RangeEnd};
 use attr;
-use codemap::{CodeMap, Spanned};
+use codemap::Spanned;
 use syntax_pos::Span;
 use errors::{DiagnosticBuilder, Handler, FatalError};
 use visit::{self, FnKind, Visitor};
@@ -831,7 +831,7 @@ impl GatedCfg {
 
     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
-        if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
+        if !has_feature(features) && !self.span.allows_unstable() {
             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
             emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
         }
@@ -841,7 +841,6 @@ impl GatedCfg {
 struct Context<'a> {
     features: &'a Features,
     parse_sess: &'a ParseSess,
-    cm: &'a CodeMap,
     plugin_attributes: &'a [(String, AttributeType)],
 }
 
@@ -850,7 +849,7 @@ macro_rules! gate_feature_fn {
         let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
-        if !has_feature && !cx.cm.span_allows_unstable(span) {
+        if !has_feature && !span.allows_unstable() {
             emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
         }
     }}
@@ -909,12 +908,8 @@ impl<'a> Context<'a> {
     }
 }
 
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
-                       cm: &CodeMap, features: &Features) {
-    let cx = Context {
-        features: features, parse_sess: parse_sess,
-        cm: cm, plugin_attributes: &[]
-    };
+pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
+    let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
     cx.check_attribute(attr, true);
 }
 
@@ -1017,7 +1012,7 @@ struct PostExpansionVisitor<'a> {
 macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
         let (cx, span) = ($cx, $span);
-        if !cx.context.cm.span_allows_unstable(span) {
+        if !span.allows_unstable() {
             gate_feature!(cx.context, $feature, span, $explain)
         }
     }}
@@ -1097,7 +1092,7 @@ fn starts_with_digit(s: &str) -> bool {
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        if !self.context.cm.span_allows_unstable(attr.span) {
+        if !attr.span.allows_unstable() {
             // check for gated attributes
             self.context.check_attribute(attr, false);
         }
@@ -1531,7 +1526,6 @@ pub fn check_crate(krate: &ast::Crate,
     let ctx = Context {
         features: features,
         parse_sess: sess,
-        cm: sess.codemap(),
         plugin_attributes: plugin_attributes,
     };
     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index fd762552248b4..dec1b7d1d87be 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -202,7 +202,7 @@ impl DiagnosticSpan {
         // backtrace ourselves, but the `macro_backtrace` helper makes
         // some decision, such as dropping some frames, and I don't
         // want to duplicate that logic here.
-        let backtrace = je.cm.macro_backtrace(span).into_iter();
+        let backtrace = span.macro_backtrace().into_iter();
         DiagnosticSpan::from_span_full(span,
                                        is_primary,
                                        label,
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 6c975f3fc4021..86ee1c5336dfe 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -125,7 +125,7 @@ pub mod ptr;
 pub mod show_span;
 pub mod std_inject;
 pub mod str;
-pub mod symbol;
+pub use syntax_pos::symbol;
 pub mod test;
 pub mod tokenstream;
 pub mod visit;
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 649e90599345b..ef7b79bccfa01 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5036,11 +5036,7 @@ impl<'a> Parser<'a> {
                                        the path:",
                                        path);
                 self.expect(&token::CloseDelim(token::Paren))?;  // `)`
-                let sp = Span {
-                    lo: start_span.lo,
-                    hi: self.prev_span.hi,
-                    expn_id: start_span.expn_id,
-                };
+                let sp = start_span.to(self.prev_span);
                 let mut err = self.span_fatal_help(sp, &msg, &suggestion);
                 err.span_suggestion(path_span, &help_msg, format!("in {}", path));
                 err.emit();  // emit diagnostic, but continue with public visibility
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index c541df9230a64..c7820a15fb3d2 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -10,29 +10,27 @@
 
 use ast;
 use attr;
+use ext::hygiene::{Mark, SyntaxContext};
 use symbol::{Symbol, keywords};
 use syntax_pos::{DUMMY_SP, Span};
 use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute};
-use parse::ParseSess;
 use ptr::P;
 use tokenstream::TokenStream;
 
 /// Craft a span that will be ignored by the stability lint's
 /// call to codemap's is_internal check.
 /// The expanded code uses the unstable `#[prelude_import]` attribute.
-fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
-    let info = ExpnInfo {
+fn ignored_span(sp: Span) -> Span {
+    let mark = Mark::fresh();
+    mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
             format: MacroAttribute(Symbol::intern("std_inject")),
             span: None,
             allow_internal_unstable: true,
         }
-    };
-    let expn_id = sess.codemap().record_expansion(info);
-    let mut sp = sp;
-    sp.expn_id = expn_id;
-    return sp;
+    });
+    Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp }
 }
 
 pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
@@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
     }
 }
 
-pub fn maybe_inject_crates_ref(sess: &ParseSess,
-                               mut krate: ast::Crate,
-                               alt_std_name: Option<String>)
-                               -> ast::Crate {
+pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<String>) -> ast::Crate {
     let name = match injected_crate_name(&krate) {
         Some(name) => name,
         None => return krate,
@@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess,
         span: DUMMY_SP,
     }));
 
-    let span = ignored_span(sess, DUMMY_SP);
+    let span = ignored_span(DUMMY_SP);
     krate.module.items.insert(0, P(ast::Item {
         attrs: vec![ast::Attribute {
             style: ast::AttrStyle::Outer,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index e052d2cda3a42..f0db50e98bc78 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -31,6 +31,7 @@ use entry::{self, EntryPointType};
 use ext::base::{ExtCtxt, Resolver};
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
+use ext::hygiene::{Mark, SyntaxContext};
 use fold::Folder;
 use util::move_map::MoveMap;
 use fold;
@@ -62,6 +63,7 @@ struct TestCtxt<'a> {
     testfns: Vec<Test>,
     reexport_test_harness_main: Option<Symbol>,
     is_test_crate: bool,
+    ctxt: SyntaxContext,
 
     // top-level re-export submodule, filled out after folding is finished
     toplevel_reexport: Option<Ident>,
@@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess,
     let mut cleaner = EntryPointCleaner { depth: 0 };
     let krate = cleaner.fold_crate(krate);
 
+    let mark = Mark::fresh();
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         span_diagnostic: sd,
@@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess,
         reexport_test_harness_main: reexport_test_harness_main,
         is_test_crate: is_test_crate(&krate),
         toplevel_reexport: None,
+        ctxt: SyntaxContext::empty().apply_mark(mark),
     };
     cx.ext_cx.crate_root = Some("std");
 
-    cx.ext_cx.bt_push(ExpnInfo {
+    mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
             format: MacroAttribute(Symbol::intern("test")),
             span: None,
-            allow_internal_unstable: false,
+            allow_internal_unstable: true,
         }
     });
 
@@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess,
 /// call to codemap's is_internal check.
 /// The expanded code calls some unstable functions in the test crate.
 fn ignored_span(cx: &TestCtxt, sp: Span) -> Span {
-    let info = ExpnInfo {
-        call_site: sp,
-        callee: NameAndSpan {
-            format: MacroAttribute(Symbol::intern("test")),
-            span: None,
-            allow_internal_unstable: true,
-        }
-    };
-    let expn_id = cx.sess.codemap().record_expansion(info);
-    let mut sp = sp;
-    sp.expn_id = expn_id;
-    return sp;
+    Span { ctxt: cx.ctxt, ..sp }
 }
 
 #[derive(PartialEq)]
diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs
index c6d6e6237f2ed..c537a0ee16644 100644
--- a/src/libsyntax/test_snippet.rs
+++ b/src/libsyntax/test_snippet.rs
@@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
     Span {
         lo: BytePos(start as u32),
         hi: BytePos(end as u32),
-        expn_id: NO_EXPANSION,
+        ctxt: NO_EXPANSION,
     }
 }
 
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index b75b3efda36c8..86bfdebe42b00 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -56,18 +56,20 @@ impl Delimited {
 
     /// Returns the opening delimiter as a token tree.
     pub fn open_tt(&self, span: Span) -> TokenTree {
-        let open_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
+        let open_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(open_span, self.open_token())
     }
 
     /// Returns the closing delimiter as a token tree.
     pub fn close_tt(&self, span: Span) -> TokenTree {
-        let close_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
+        let close_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(close_span, self.close_token())
     }
@@ -425,7 +427,7 @@ mod tests {
         Span {
             lo: BytePos(a),
             hi: BytePos(b),
-            expn_id: NO_EXPANSION,
+            ctxt: NO_EXPANSION,
         }
     }
 
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 767ec94a0ce61..923e8072f4346 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -13,7 +13,6 @@
 use self::State::*;
 
 use syntax::ast;
-use syntax::codemap;
 use syntax::ext::base;
 use syntax::ext::base::*;
 use syntax::feature_gate;
@@ -240,15 +239,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
         }
     }
 
-    let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
-        call_site: sp,
-        callee: codemap::NameAndSpan {
-            format: codemap::MacroBang(Symbol::intern("asm")),
-            span: None,
-            allow_internal_unstable: false,
-        },
-    });
-
     MacEager::expr(P(ast::Expr {
         id: ast::DUMMY_NODE_ID,
         node: ast::ExprKind::InlineAsm(P(ast::InlineAsm {
@@ -260,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
             volatile: volatile,
             alignstack: alignstack,
             dialect: dialect,
-            expn_id: expn_id,
+            ctxt: cx.backtrace(),
         })),
         span: sp,
         attrs: ast::ThinVec::new(),
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
index d14b59d6c70e2..1993d6ebe5b49 100644
--- a/src/libsyntax_ext/deriving/clone.rs
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -111,7 +111,7 @@ fn cs_clone_shallow(name: &str,
                         ty: P<ast::Ty>, span: Span, helper_name: &str) {
         // Generate statement `let _: helper_name<ty>;`,
         // set the expn ID so we can use the unstable struct.
-        let span = super::allow_unstable(cx, span, "derive(Clone)");
+        let span = Span { ctxt: cx.backtrace(), ..span};
         let assert_path = cx.path_all(span, true,
                                         cx.std_path(&["clone", helper_name]),
                                         vec![], vec![ty], vec![]);
diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs
index 6ab5987a159ca..eef21492debc3 100644
--- a/src/libsyntax_ext/deriving/cmp/eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/eq.rs
@@ -58,7 +58,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
                         ty: P<ast::Ty>, span: Span, helper_name: &str) {
         // Generate statement `let _: helper_name<ty>;`,
         // set the expn ID so we can use the unstable struct.
-        let span = super::allow_unstable(cx, span, "derive(Eq)");
+        let span = Span { ctxt: cx.backtrace(), ..span };
         let assert_path = cx.path_all(span, true,
                                         cx.std_path(&["cmp", helper_name]),
                                         vec![], vec![ty], vec![]);
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index a767716466cb1..ec4cb815960d1 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -66,8 +66,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<E
         StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"),
     };
 
-    // We want to make sure we have the expn_id set so that we can use unstable methods
-    let span = Span { expn_id: cx.backtrace(), ..span };
+    // We want to make sure we have the ctxt set so that we can use unstable methods
+    let span = Span { ctxt: cx.backtrace(), ..span };
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
     let builder = Ident::from_str("builder");
     let builder_expr = cx.expr_ident(span, builder.clone());
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 48e7ff0d24370..1ff0fec1c96a6 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -375,7 +375,7 @@ fn find_type_parameters(ty: &ast::Ty,
         }
 
         fn visit_mac(&mut self, mac: &ast::Mac) {
-            let span = Span { expn_id: self.span.expn_id, ..mac.span };
+            let span = Span { ctxt: self.span.ctxt, ..mac.span };
             self.cx.span_err(span, "`derive` cannot be used on items with type macros");
         }
     }
@@ -1458,7 +1458,7 @@ impl<'a> MethodDef<'a> {
             .iter()
             .map(|v| {
                 let ident = v.node.name;
-                let sp = Span { expn_id: trait_.span.expn_id, ..v.span };
+                let sp = Span { ctxt: trait_.span.ctxt, ..v.span };
                 let summary = trait_.summarise_struct(cx, &v.node.data);
                 (ident, sp, summary)
             })
@@ -1478,7 +1478,7 @@ impl<'a> TraitDef<'a> {
         let mut named_idents = Vec::new();
         let mut just_spans = Vec::new();
         for field in struct_def.fields() {
-            let sp = Span { expn_id: self.span.expn_id, ..field.span };
+            let sp = Span { ctxt: self.span.ctxt, ..field.span };
             match field.ident {
                 Some(ident) => named_idents.push((ident, sp)),
                 _ => just_spans.push(sp),
@@ -1523,7 +1523,7 @@ impl<'a> TraitDef<'a> {
         let mut paths = Vec::new();
         let mut ident_exprs = Vec::new();
         for (i, struct_field) in struct_def.fields().iter().enumerate() {
-            let sp = Span { expn_id: self.span.expn_id, ..struct_field.span };
+            let sp = Span { ctxt: self.span.ctxt, ..struct_field.span };
             let ident = cx.ident_of(&format!("{}_{}", prefix, i));
             paths.push(codemap::Spanned {
                 span: sp,
@@ -1544,7 +1544,7 @@ impl<'a> TraitDef<'a> {
                             cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
                         }
                         codemap::Spanned {
-                            span: Span { expn_id: self.span.expn_id, ..pat.span },
+                            span: Span { ctxt: self.span.ctxt, ..pat.span },
                             node: ast::FieldPat {
                                 ident: ident.unwrap(),
                                 pat: pat,
@@ -1576,7 +1576,7 @@ impl<'a> TraitDef<'a> {
          mutbl: ast::Mutability)
          -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
         let variant_ident = variant.node.name;
-        let sp = Span { expn_id: self.span.expn_id, ..variant.span };
+        let sp = Span { ctxt: self.span.ctxt, ..variant.span };
         let variant_path = cx.path(sp, vec![enum_ident, variant_ident]);
         self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl)
     }
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index b51591bf89d5e..b2bb43e41ed9e 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -12,9 +12,9 @@
 
 use std::rc::Rc;
 use syntax::ast;
-use syntax::codemap;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
 use syntax::ext::build::AstBuilder;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -74,20 +74,6 @@ pub mod ord;
 
 pub mod generic;
 
-fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
-    Span {
-        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
-            call_site: span,
-            callee: codemap::NameAndSpan {
-                format: codemap::MacroAttribute(Symbol::intern(attr_name)),
-                span: Some(span),
-                allow_internal_unstable: true,
-            },
-        }),
-        ..span
-    }
-}
-
 macro_rules! derive_traits {
     ($( $name:expr => $func:path, )+) => {
         pub fn is_builtin_trait(name: ast::Name) -> bool {
@@ -177,15 +163,15 @@ fn call_intrinsic(cx: &ExtCtxt,
                   intrinsic: &str,
                   args: Vec<P<ast::Expr>>)
                   -> P<ast::Expr> {
-    span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
-        call_site: span,
-        callee: codemap::NameAndSpan {
-            format: codemap::MacroAttribute(Symbol::intern("derive")),
-            span: Some(span),
-            allow_internal_unstable: true,
-        },
-    });
-
+    if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable {
+        span.ctxt = cx.backtrace();
+    } else { // Avoid instability errors with user defined curstom derives, cc #36316
+        let mut info = cx.current_expansion.mark.expn_info().unwrap();
+        info.callee.allow_internal_unstable = true;
+        let mark = Mark::fresh();
+        mark.set_expn_info(info);
+        span.ctxt = SyntaxContext::empty().apply_mark(mark);
+    }
     let path = cx.std_path(&["intrinsics", intrinsic]);
     let call = cx.expr_call_global(span, path, args);
 
diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs
index 2d815b3f1bb7d..bb89caab709b0 100644
--- a/src/libsyntax_ext/proc_macro_registrar.rs
+++ b/src/libsyntax_ext/proc_macro_registrar.rs
@@ -17,6 +17,7 @@ use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
 use syntax::ext::base::ExtCtxt;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::fold::Folder;
 use syntax::parse::ParseSess;
 use syntax::ptr::P;
@@ -360,7 +361,8 @@ fn mk_registrar(cx: &mut ExtCtxt,
                 custom_derives: &[ProcMacroDerive],
                 custom_attrs: &[ProcMacroDef],
                 custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
-    let eid = cx.codemap().record_expansion(ExpnInfo {
+    let mark = Mark::fresh();
+    mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
             format: MacroAttribute(Symbol::intern("proc_macro")),
@@ -368,7 +370,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
             allow_internal_unstable: true,
         }
     });
-    let span = Span { expn_id: eid, ..DUMMY_SP };
+    let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP };
 
     let proc_macro = Ident::from_str("proc_macro");
     let krate = cx.item(span,
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index feebbcd6f03b6..8a9ff647b3ea1 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -15,12 +15,16 @@
 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
 //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
 
+use Span;
+use symbol::Symbol;
+
+use serialize::{Encodable, Decodable, Encoder, Decoder};
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 
 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SyntaxContext(u32);
 
 #[derive(Copy, Clone)]
@@ -36,8 +40,8 @@ pub struct Mark(u32);
 impl Mark {
     pub fn fresh() -> Self {
         HygieneData::with(|data| {
-            let next_mark = Mark(data.next_mark.0 + 1);
-            ::std::mem::replace(&mut data.next_mark, next_mark)
+            data.marks.push(None);
+            Mark(data.marks.len() as u32 - 1)
         })
     }
 
@@ -53,23 +57,31 @@ impl Mark {
     pub fn from_u32(raw: u32) -> Mark {
         Mark(raw)
     }
+
+    pub fn expn_info(self) -> Option<ExpnInfo> {
+        HygieneData::with(|data| data.marks[self.0 as usize].clone())
+    }
+
+    pub fn set_expn_info(self, info: ExpnInfo) {
+        HygieneData::with(|data| data.marks[self.0 as usize] = Some(info))
+    }
 }
 
 struct HygieneData {
+    marks: Vec<Option<ExpnInfo>>,
     syntax_contexts: Vec<SyntaxContextData>,
     markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
-    next_mark: Mark,
 }
 
 impl HygieneData {
     fn new() -> Self {
         HygieneData {
+            marks: vec![None],
             syntax_contexts: vec![SyntaxContextData {
                 outer_mark: Mark::root(),
                 prev_ctxt: SyntaxContext::empty(),
             }],
             markings: HashMap::new(),
-            next_mark: Mark(1),
         }
     }
 
@@ -81,8 +93,8 @@ impl HygieneData {
     }
 }
 
-pub fn reset_hygiene_data() {
-    HygieneData::with(|data| *data = HygieneData::new())
+pub fn clear_markings() {
+    HygieneData::with(|data| data.markings = HashMap::new());
 }
 
 impl SyntaxContext {
@@ -113,6 +125,10 @@ impl SyntaxContext {
             })
         })
     }
+
+    pub fn outer(self) -> Mark {
+        HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
+    }
 }
 
 impl fmt::Debug for SyntaxContext {
@@ -120,3 +136,67 @@ impl fmt::Debug for SyntaxContext {
         write!(f, "#{}", self.0)
     }
 }
+
+/// Extra information for tracking spans of macro and syntax sugar expansion
+#[derive(Clone, Hash, Debug)]
+pub struct ExpnInfo {
+    /// The location of the actual macro invocation or syntax sugar , e.g.
+    /// `let x = foo!();` or `if let Some(y) = x {}`
+    ///
+    /// This may recursively refer to other macro invocations, e.g. if
+    /// `foo!()` invoked `bar!()` internally, and there was an
+    /// expression inside `bar!`; the call_site of the expression in
+    /// the expansion would point to the `bar!` invocation; that
+    /// call_site span would have its own ExpnInfo, with the call_site
+    /// pointing to the `foo!` invocation.
+    pub call_site: Span,
+    /// Information about the expansion.
+    pub callee: NameAndSpan
+}
+
+#[derive(Clone, Hash, Debug)]
+pub struct NameAndSpan {
+    /// The format with which the macro was invoked.
+    pub format: ExpnFormat,
+    /// Whether the macro is allowed to use #[unstable]/feature-gated
+    /// features internally without forcing the whole crate to opt-in
+    /// to them.
+    pub allow_internal_unstable: bool,
+    /// The span of the macro definition itself. The macro may not
+    /// have a sensible definition span (e.g. something defined
+    /// completely inside libsyntax) in which case this is None.
+    pub span: Option<Span>
+}
+
+impl NameAndSpan {
+    pub fn name(&self) -> Symbol {
+        match self.format {
+            ExpnFormat::MacroAttribute(s) |
+            ExpnFormat::MacroBang(s) |
+            ExpnFormat::CompilerDesugaring(s) => s,
+        }
+    }
+}
+
+/// The source of expansion.
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
+pub enum ExpnFormat {
+    /// e.g. #[derive(...)] <item>
+    MacroAttribute(Symbol),
+    /// e.g. `format!()`
+    MacroBang(Symbol),
+    /// Desugaring done by the compiler during HIR lowering.
+    CompilerDesugaring(Symbol)
+}
+
+impl Encodable for SyntaxContext {
+    fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
+        Ok(()) // FIXME(jseyfried) intercrate hygiene
+    }
+}
+
+impl Decodable for SyntaxContext {
+    fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
+        Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
+    }
+}
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 1b62d62348bc8..9b45e364ecf34 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -25,6 +25,7 @@
 
 #![feature(const_fn)]
 #![feature(custom_attribute)]
+#![feature(optin_builtin_traits)]
 #![allow(unused_attributes)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -43,6 +44,9 @@ extern crate serialize;
 extern crate serialize as rustc_serialize; // used by deriving
 
 pub mod hygiene;
+pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan};
+
+pub mod symbol;
 
 pub type FileName = String;
 
@@ -60,7 +64,7 @@ pub struct Span {
     pub hi: BytePos,
     /// Information about where the macro came from, if this piece of
     /// code was created by a macro expansion.
-    pub expn_id: ExpnId
+    pub ctxt: SyntaxContext,
 }
 
 /// A collection of spans. Spans have two orthogonal attributes:
@@ -79,7 +83,7 @@ impl Span {
     /// Returns a new span representing just the end-point of this span
     pub fn end_point(self) -> Span {
         let lo = cmp::max(self.hi.0 - 1, self.lo.0);
-        Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id}
+        Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt }
     }
 
     /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
@@ -107,6 +111,69 @@ impl Span {
             None
         }
     }
+
+    /// Return the source span - this is either the supplied span, or the span for
+    /// the macro callsite that expanded to it.
+    pub fn source_callsite(self) -> Span {
+        self.ctxt.outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self)
+    }
+
+    /// Return the source callee.
+    ///
+    /// Returns None if the supplied span has no expansion trace,
+    /// else returns the NameAndSpan for the macro definition
+    /// corresponding to the source callsite.
+    pub fn source_callee(self) -> Option<NameAndSpan> {
+        fn source_callee(info: ExpnInfo) -> NameAndSpan {
+            match info.call_site.ctxt.outer().expn_info() {
+                Some(info) => source_callee(info),
+                None => info.callee,
+            }
+        }
+        self.ctxt.outer().expn_info().map(source_callee)
+    }
+
+    /// Check if a span is "internal" to a macro in which #[unstable]
+    /// items can be used (that is, a macro marked with
+    /// `#[allow_internal_unstable]`).
+    pub fn allows_unstable(&self) -> bool {
+        match self.ctxt.outer().expn_info() {
+            Some(info) => info.callee.allow_internal_unstable,
+            None => false,
+        }
+    }
+
+    pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
+        let mut prev_span = DUMMY_SP;
+        let mut result = vec![];
+        loop {
+            let info = match self.ctxt.outer().expn_info() {
+                Some(info) => info,
+                None => break,
+            };
+
+            let (pre, post) = match info.callee.format {
+                ExpnFormat::MacroAttribute(..) => ("#[", "]"),
+                ExpnFormat::MacroBang(..) => ("", "!"),
+                ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"),
+            };
+            let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post);
+            let def_site_span = info.callee.span;
+
+            // Don't print recursive invocations
+            if !info.call_site.source_equal(&prev_span) {
+                result.push(MacroBacktrace {
+                    call_site: info.call_site,
+                    macro_decl_name: macro_decl_name,
+                    def_site_span: def_site_span,
+                });
+            }
+
+            prev_span = self;
+            self = info.call_site;
+        }
+        result
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -147,8 +214,8 @@ impl serialize::UseSpecializedDecodable for Span {
 }
 
 fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
-    write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}",
-           span.lo, span.hi, span.expn_id)
+    write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}",
+           span.lo, span.hi, span.ctxt)
 }
 
 impl fmt::Debug for Span {
@@ -157,12 +224,7 @@ impl fmt::Debug for Span {
     }
 }
 
-pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION };
-
-// Generic span to be used for code originating from the command line
-pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0),
-                                         hi: BytePos(0),
-                                         expn_id: COMMAND_LINE_EXPN };
+pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION };
 
 impl MultiSpan {
     pub fn new() -> MultiSpan {
@@ -256,22 +318,7 @@ impl From<Span> for MultiSpan {
     }
 }
 
-#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)]
-pub struct ExpnId(pub u32);
-
-pub const NO_EXPANSION: ExpnId = ExpnId(!0);
-// For code appearing from the command line
-pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
-
-impl ExpnId {
-    pub fn from_u32(id: u32) -> ExpnId {
-        ExpnId(id)
-    }
-
-    pub fn into_u32(self) -> u32 {
-        self.0
-    }
-}
+pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
 
 /// Identifies an offset of a multi-byte character in a FileMap
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)]
@@ -651,7 +698,7 @@ thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::
 
 /* assuming that we're not in macro expansion */
 pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
-    Span {lo: lo, hi: hi, expn_id: NO_EXPANSION}
+    Span {lo: lo, hi: hi, ctxt: NO_EXPANSION}
 }
 
 pub struct MacroBacktrace {
diff --git a/src/libsyntax/symbol.rs b/src/libsyntax_pos/symbol.rs
similarity index 86%
rename from src/libsyntax/symbol.rs
rename to src/libsyntax_pos/symbol.rs
index 6642c60d256b3..ee022ad326377 100644
--- a/src/libsyntax/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -12,11 +12,58 @@
 //! allows bidirectional lookup; i.e. given a value, one can easily find the
 //! type, and vice versa.
 
+use hygiene::SyntaxContext;
+
 use serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Ident {
+    pub name: Symbol,
+    pub ctxt: SyntaxContext,
+}
+
+impl Ident {
+    pub const fn with_empty_ctxt(name: Symbol) -> Ident {
+        Ident { name: name, ctxt: SyntaxContext::empty() }
+    }
+
+    /// Maps a string to an identifier with an empty syntax context.
+    pub fn from_str(string: &str) -> Ident {
+        Ident::with_empty_ctxt(Symbol::intern(string))
+    }
+
+    pub fn unhygienize(self) -> Ident {
+        Ident { name: self.name, ctxt: SyntaxContext::empty() }
+    }
+}
+
+impl fmt::Debug for Ident {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}{:?}", self.name, self.ctxt)
+    }
+}
+
+impl fmt::Display for Ident {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.name, f)
+    }
+}
+
+impl Encodable for Ident {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        self.name.encode(s)
+    }
+}
+
+impl Decodable for Ident {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
+        Ok(Ident::with_empty_ctxt(Symbol::decode(d)?))
+    }
+}
+
 /// A symbol is an interned or gensymed string.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Symbol(u32);
@@ -128,19 +175,19 @@ macro_rules! declare_keywords {(
     $( ($index: expr, $konst: ident, $string: expr) )*
 ) => {
     pub mod keywords {
-        use ast;
+        use super::{Symbol, Ident};
         #[derive(Clone, Copy, PartialEq, Eq)]
         pub struct Keyword {
-            ident: ast::Ident,
+            ident: Ident,
         }
         impl Keyword {
-            #[inline] pub fn ident(self) -> ast::Ident { self.ident }
-            #[inline] pub fn name(self) -> ast::Name { self.ident.name }
+            #[inline] pub fn ident(self) -> Ident { self.ident }
+            #[inline] pub fn name(self) -> Symbol { self.ident.name }
         }
         $(
             #[allow(non_upper_case_globals)]
             pub const $konst: Keyword = Keyword {
-                ident: ast::Ident::with_empty_ctxt(super::Symbol($index))
+                ident: Ident::with_empty_ctxt(super::Symbol($index))
             };
         )*
     }
diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs
index bd25561065bea..272bf1150cacb 100644
--- a/src/test/compile-fail-fulldeps/qquote.rs
+++ b/src/test/compile-fail-fulldeps/qquote.rs
@@ -27,14 +27,6 @@ fn main() {
         &ps,
         syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
         &mut resolver);
-    cx.bt_push(syntax::codemap::ExpnInfo {
-        call_site: DUMMY_SP,
-        callee: syntax::codemap::NameAndSpan {
-            format: syntax::codemap::MacroBang(Symbol::intern("")),
-            allow_internal_unstable: false,
-            span: None,
-        }
-    });
     let cx = &mut cx;
 
     assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs
index d692bb519c149..5518ab47c2bd2 100644
--- a/src/test/run-fail-fulldeps/qquote.rs
+++ b/src/test/run-fail-fulldeps/qquote.rs
@@ -30,14 +30,6 @@ fn main() {
         &ps,
         syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
         &mut resolver);
-    cx.bt_push(syntax::codemap::ExpnInfo {
-        call_site: DUMMY_SP,
-        callee: syntax::codemap::NameAndSpan {
-            format: syntax::codemap::MacroBang(Symbol::intern("")),
-            allow_internal_unstable: false,
-            span: None,
-        }
-    });
     let cx = &mut cx;
 
     println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23)));
diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs
index b4ed57192ccf6..4a8246ec429c0 100644
--- a/src/test/run-pass-fulldeps/qquote.rs
+++ b/src/test/run-pass-fulldeps/qquote.rs
@@ -26,14 +26,6 @@ fn main() {
         &ps,
         syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
         &mut resolver);
-    cx.bt_push(syntax::codemap::ExpnInfo {
-        call_site: DUMMY_SP,
-        callee: syntax::codemap::NameAndSpan {
-            format: syntax::codemap::MacroBang(Symbol::intern("")),
-            allow_internal_unstable: false,
-            span: None,
-        }
-    });
     let cx = &mut cx;
 
     macro_rules! check {

From 8c49446fa029590312c591818c0776b6ab7bc472 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Wed, 15 Mar 2017 00:22:48 +0000
Subject: [PATCH 10/14] Refactor how spans are combined in the parser.

---
 src/librustc_metadata/cstore_impl.rs          |   4 +-
 src/librustc_metadata/decoder.rs              |   6 +-
 src/librustc_save_analysis/lib.rs             |   2 +-
 src/librustc_save_analysis/span_utils.rs      |   4 +-
 src/libsyntax/ast.rs                          |  10 +-
 src/libsyntax/attr.rs                         |  15 +-
 src/libsyntax/codemap.rs                      |   4 -
 src/libsyntax/ext/tt/macro_parser.rs          |   9 +-
 src/libsyntax/parse/attr.rs                   |  29 +-
 src/libsyntax/parse/lexer/mod.rs              |  42 +-
 src/libsyntax/parse/lexer/unicode_chars.rs    |   4 +-
 src/libsyntax/parse/mod.rs                    |   6 +-
 src/libsyntax/parse/parser.rs                 | 617 ++++++++----------
 src/libsyntax_pos/lib.rs                      |  12 +-
 src/test/compile-fail/imports/macro-paths.rs  |   2 -
 src/test/compile-fail/imports/macros.rs       |   2 -
 src/test/compile-fail/issue-25385.rs          |   1 -
 .../run-pass/syntax-extension-source-utils.rs |   2 +-
 .../macros/macro_path_as_generic_bound.stderr |   5 +-
 19 files changed, 353 insertions(+), 423 deletions(-)

diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 2a67b79eaa52e..6edd05c803402 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -36,7 +36,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::parse::filemap_to_stream;
 use syntax::symbol::Symbol;
-use syntax_pos::{mk_sp, Span};
+use syntax_pos::{Span, NO_EXPANSION};
 use rustc::hir::svh::Svh;
 use rustc_back::target::Target;
 use rustc::hir;
@@ -400,7 +400,7 @@ impl CrateStore for cstore::CStore {
         let source_name = format!("<{} macros>", name);
 
         let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body);
-        let local_span = mk_sp(filemap.start_pos, filemap.end_pos);
+        let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION };
         let body = filemap_to_stream(&sess.parse_sess, filemap);
 
         // Mark the attrs as used
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 6ccdf8092f210..d9fa1ff933611 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -39,7 +39,7 @@ use syntax::attr;
 use syntax::ast;
 use syntax::codemap;
 use syntax::ext::base::MacroKind;
-use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
+use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION};
 
 pub struct DecodeContext<'a, 'tcx: 'a> {
     opaque: opaque::Decoder<'a>,
@@ -243,7 +243,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
         let sess = if let Some(sess) = self.sess {
             sess
         } else {
-            return Ok(syntax_pos::mk_sp(lo, hi));
+            return Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION });
         };
 
         let (lo, hi) = if lo > hi {
@@ -290,7 +290,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
         let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos;
         let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos;
 
-        Ok(syntax_pos::mk_sp(lo, hi))
+        Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION })
     }
 }
 
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index e2eee0a16006a..06cc563b7278d 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -741,7 +741,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let ident_start = text.find(&name).expect("Name not in signature?");
         let ident_end = ident_start + name.len();
         Signature {
-            span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)),
+            span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span },
             text: text,
             ident_start: ident_start,
             ident_end: ident_end,
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index c19f805a28575..af3efb4809081 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -305,10 +305,10 @@ impl<'a> SpanUtils<'a> {
                 continue;
             }
             if let TokenTree::Token(_, token::Semi) = tok {
-                return self.snippet(mk_sp(first_span.lo, prev.span().hi));
+                return self.snippet(first_span.to(prev.span()));
             } else if let TokenTree::Delimited(_, ref d) = tok {
                 if d.delim == token::Brace {
-                    return self.snippet(mk_sp(first_span.lo, prev.span().hi));
+                    return self.snippet(first_span.to(prev.span()));
                 }
             }
             prev = tok;
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a4bebd311ded2..9eb86aa006d17 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -17,7 +17,7 @@ pub use self::PathParameters::*;
 pub use symbol::{Ident, Symbol as Name};
 pub use util::ThinVec;
 
-use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
 use codemap::{respan, Spanned};
 use abi::Abi;
 use ext::hygiene::{Mark, SyntaxContext};
@@ -1433,7 +1433,7 @@ impl Arg {
                     TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => {
                         Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
                     }
-                    _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
+                    _ => Some(respan(self.pat.span.to(self.ty.span),
                                      SelfKind::Explicit(self.ty.clone(), mutbl))),
                 }
             }
@@ -1450,7 +1450,7 @@ impl Arg {
     }
 
     pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
-        let span = mk_sp(eself.span.lo, eself_ident.span.hi);
+        let span = eself.span.to(eself_ident.span);
         let infer_ty = P(Ty {
             id: DUMMY_NODE_ID,
             node: TyKind::ImplicitSelf,
@@ -1687,11 +1687,11 @@ pub struct PolyTraitRef {
 }
 
 impl PolyTraitRef {
-    pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, lo: BytePos, hi: BytePos) -> Self {
+    pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, span: Span) -> Self {
         PolyTraitRef {
             bound_lifetimes: lifetimes,
             trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID },
-            span: mk_sp(lo, hi),
+            span: span,
         }
     }
 }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 2f1efd6ad00ee..5dcce2572af87 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -18,8 +18,8 @@ use ast;
 use ast::{AttrId, Attribute, Name, Ident};
 use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
 use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
-use codemap::{Spanned, spanned, dummy_spanned, mk_sp};
-use syntax_pos::{Span, BytePos, DUMMY_SP};
+use codemap::{Spanned, respan, dummy_spanned};
+use syntax_pos::{Span, DUMMY_SP};
 use errors::Handler;
 use feature_gate::{Features, GatedCfg};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
@@ -447,17 +447,16 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute
     }
 }
 
-pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos)
-                           -> Attribute {
+pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute {
     let style = doc_comment_style(&text.as_str());
-    let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked));
+    let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked));
     Attribute {
         id: id,
         style: style,
-        path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")),
-        tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)),
+        path: ast::Path::from_ident(span, ast::Ident::from_str("doc")),
+        tokens: MetaItemKind::NameValue(lit).tokens(span),
         is_sugared_doc: true,
-        span: mk_sp(lo, hi),
+        span: span,
     }
 }
 
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index ba199eacb6276..4d67390d44234 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -49,10 +49,6 @@ pub struct Spanned<T> {
     pub span: Span,
 }
 
-pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
-    respan(mk_sp(lo, hi), t)
-}
-
 pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
     Spanned {node: t, span: sp}
 }
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index ed17f0f956cf3..9ee427eed3556 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -79,7 +79,7 @@ pub use self::ParseResult::*;
 use self::TokenTreeOrTokenTreeVec::*;
 
 use ast::Ident;
-use syntax_pos::{self, BytePos, mk_sp, Span};
+use syntax_pos::{self, BytePos, Span};
 use codemap::Spanned;
 use errors::FatalError;
 use ext::tt::quoted::{self, TokenTree};
@@ -285,7 +285,7 @@ fn inner_parse_loop(sess: &ParseSess,
                     eof_eis: &mut SmallVector<Box<MatcherPos>>,
                     bb_eis: &mut SmallVector<Box<MatcherPos>>,
                     token: &Token,
-                    span: &syntax_pos::Span)
+                    span: syntax_pos::Span)
                     -> ParseResult<()> {
     while let Some(mut ei) = cur_eis.pop() {
         // When unzipped trees end, remove them
@@ -323,8 +323,7 @@ fn inner_parse_loop(sess: &ParseSess,
                     for idx in ei.match_lo..ei.match_hi {
                         let sub = ei.matches[idx].clone();
                         new_pos.matches[idx]
-                            .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo,
-                                                                span.hi))));
+                            .push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span })));
                     }
 
                     new_pos.match_cur = ei.match_hi;
@@ -426,7 +425,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op
         assert!(next_eis.is_empty());
 
         match inner_parse_loop(sess, &mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis,
-                               &parser.token, &parser.span) {
+                               &parser.token, parser.span) {
             Success(_) => {},
             Failure(sp, tok) => return Failure(sp, tok),
             Error(sp, msg) => return Error(sp, msg),
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 53106214fa310..92cec462ffb7c 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -10,8 +10,7 @@
 
 use attr;
 use ast;
-use syntax_pos::{mk_sp, Span};
-use codemap::spanned;
+use codemap::respan;
 use parse::common::SeqSep;
 use parse::PResult;
 use parse::token::{self, Nonterminal};
@@ -49,8 +48,7 @@ impl<'a> Parser<'a> {
                     just_parsed_doc_comment = false;
                 }
                 token::DocComment(s) => {
-                    let Span { lo, hi, .. } = self.span;
-                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi);
+                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
                     if attr.style != ast::AttrStyle::Outer {
                         let mut err = self.fatal("expected outer doc comment");
                         err.note("inner doc comments like this (starting with \
@@ -94,7 +92,7 @@ impl<'a> Parser<'a> {
                self.token);
         let (span, path, tokens, mut style) = match self.token {
             token::Pound => {
-                let lo = self.span.lo;
+                let lo = self.span;
                 self.bump();
 
                 if inner_parse_policy == InnerAttributeParsePolicy::Permitted {
@@ -122,9 +120,9 @@ impl<'a> Parser<'a> {
                 self.expect(&token::OpenDelim(token::Bracket))?;
                 let (path, tokens) = self.parse_path_and_tokens()?;
                 self.expect(&token::CloseDelim(token::Bracket))?;
-                let hi = self.prev_span.hi;
+                let hi = self.prev_span;
 
-                (mk_sp(lo, hi), path, tokens, style)
+                (lo.to(hi), path, tokens, style)
             }
             _ => {
                 let token_str = self.this_token_to_string();
@@ -189,8 +187,7 @@ impl<'a> Parser<'a> {
                 }
                 token::DocComment(s) => {
                     // we need to get the position of this token before we bump.
-                    let Span { lo, hi, .. } = self.span;
-                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi);
+                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
                     if attr.style == ast::AttrStyle::Inner {
                         attrs.push(attr);
                         self.bump();
@@ -238,11 +235,10 @@ impl<'a> Parser<'a> {
             return Ok(meta);
         }
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let ident = self.parse_ident()?;
         let node = self.parse_meta_item_kind()?;
-        let hi = self.prev_span.hi;
-        Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) })
+        Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) })
     }
 
     pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
@@ -258,26 +254,25 @@ impl<'a> Parser<'a> {
 
     /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
     fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
-        let sp = self.span;
-        let lo = self.span.lo;
+        let lo = self.span;
 
         match self.parse_unsuffixed_lit() {
             Ok(lit) => {
-                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit)))
+                return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
 
         match self.parse_meta_item() {
             Ok(mi) => {
-                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
+                return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
 
         let found = self.this_token_to_string();
         let msg = format!("expected unsuffixed literal or identifier, found {}", found);
-        Err(self.diagnostic().struct_span_err(sp, &msg))
+        Err(self.diagnostic().struct_span_err(lo, &msg))
     }
 
     /// matches meta_seq = ( COMMASEP(meta_item_inner) )
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index d48cf6911ed37..920b2c401e2bd 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast::{self, Ident};
-use syntax_pos::{self, BytePos, CharPos, Pos, Span};
+use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
 use codemap::CodeMap;
 use errors::{FatalError, DiagnosticBuilder};
 use parse::{token, ParseSess};
@@ -68,6 +68,10 @@ pub struct StringReader<'a> {
     open_braces: Vec<(token::DelimToken, Span)>,
 }
 
+fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
+    Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }
+}
+
 impl<'a> StringReader<'a> {
     fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
         let res = self.try_next_token();
@@ -225,12 +229,12 @@ impl<'a> StringReader<'a> {
 
     /// Report a fatal error spanning [`from_pos`, `to_pos`).
     fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
-        self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m)
+        self.fatal_span(mk_sp(from_pos, to_pos), m)
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`).
     fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
-        self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m)
+        self.err_span(mk_sp(from_pos, to_pos), m)
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
@@ -254,7 +258,7 @@ impl<'a> StringReader<'a> {
         for c in c.escape_default() {
             m.push(c)
         }
-        self.sess.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
+        self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..])
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
@@ -278,7 +282,7 @@ impl<'a> StringReader<'a> {
         for c in c.escape_default() {
             m.push(c)
         }
-        self.sess.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
+        self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..])
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the
@@ -302,11 +306,11 @@ impl<'a> StringReader<'a> {
             None => {
                 if self.is_eof() {
                     self.peek_tok = token::Eof;
-                    self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
+                    self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos);
                 } else {
                     let start_bytepos = self.pos;
                     self.peek_tok = self.next_token_inner()?;
-                    self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos);
+                    self.peek_span = mk_sp(start_bytepos, self.pos);
                 };
             }
         }
@@ -489,7 +493,7 @@ impl<'a> StringReader<'a> {
         if let Some(c) = self.ch {
             if c.is_whitespace() {
                 let msg = "called consume_any_line_comment, but there was whitespace";
-                self.sess.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), msg);
+                self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg);
             }
         }
 
@@ -532,13 +536,13 @@ impl<'a> StringReader<'a> {
 
                             Some(TokenAndSpan {
                                 tok: tok,
-                                sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                                sp: mk_sp(start_bpos, self.pos),
                             })
                         })
                     } else {
                         Some(TokenAndSpan {
                             tok: token::Comment,
-                            sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                            sp: mk_sp(start_bpos, self.pos),
                         })
                     };
                 }
@@ -571,7 +575,7 @@ impl<'a> StringReader<'a> {
                     }
                     return Some(TokenAndSpan {
                         tok: token::Shebang(self.name_from(start)),
-                        sp: syntax_pos::mk_sp(start, self.pos),
+                        sp: mk_sp(start, self.pos),
                     });
                 }
             }
@@ -599,7 +603,7 @@ impl<'a> StringReader<'a> {
                 }
                 let c = Some(TokenAndSpan {
                     tok: token::Whitespace,
-                    sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                    sp: mk_sp(start_bpos, self.pos),
                 });
                 debug!("scanning whitespace: {:?}", c);
                 c
@@ -661,7 +665,7 @@ impl<'a> StringReader<'a> {
 
             Some(TokenAndSpan {
                 tok: tok,
-                sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                sp: mk_sp(start_bpos, self.pos),
             })
         })
     }
@@ -858,7 +862,7 @@ impl<'a> StringReader<'a> {
                                 let valid = if self.ch_is('{') {
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
-                                    let span = syntax_pos::mk_sp(start, self.pos);
+                                    let span = mk_sp(start, self.pos);
                                     self.sess.span_diagnostic
                                         .struct_span_err(span, "incorrect unicode escape sequence")
                                         .span_help(span,
@@ -896,13 +900,13 @@ impl<'a> StringReader<'a> {
                                                                         },
                                                                         c);
                                 if e == '\r' {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
+                                    err.span_help(mk_sp(escaped_pos, pos),
                                                   "this is an isolated carriage return; consider \
                                                    checking your editor and version control \
                                                    settings");
                                 }
                                 if (e == '{' || e == '}') && !ascii_only {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
+                                    err.span_help(mk_sp(escaped_pos, pos),
                                                   "if used in a formatting string, curly braces \
                                                    are escaped with `{{` and `}}`");
                                 }
@@ -1735,7 +1739,7 @@ mod tests {
             sp: Span {
                 lo: BytePos(21),
                 hi: BytePos(23),
-                expn_id: NO_EXPANSION,
+                ctxt: NO_EXPANSION,
             },
         };
         assert_eq!(tok1, tok2);
@@ -1749,7 +1753,7 @@ mod tests {
             sp: Span {
                 lo: BytePos(24),
                 hi: BytePos(28),
-                expn_id: NO_EXPANSION,
+                ctxt: NO_EXPANSION,
             },
         };
         assert_eq!(tok3, tok4);
@@ -1908,7 +1912,7 @@ mod tests {
         let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
         let comment = lexer.next_token();
         assert_eq!(comment.tok, token::Comment);
-        assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7)));
+        assert_eq!((comment.sp.lo, comment.sp.hi), (BytePos(0), BytePos(7)));
         assert_eq!(lexer.next_token().tok, token::Whitespace);
         assert_eq!(lexer.next_token().tok,
                    token::DocComment(Symbol::intern("/// test")));
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index 6da3e5de75cdc..4df23da3c9ce3 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -11,7 +11,7 @@
 // Characters and their corresponding confusables were collected from
 // http://www.unicode.org/Public/security/revision-06/confusables.txt
 
-use syntax_pos::mk_sp as make_span;
+use syntax_pos::{Span, NO_EXPANSION};
 use errors::DiagnosticBuilder;
 use super::StringReader;
 
@@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>,
     .iter()
     .find(|&&(c, _, _)| c == ch)
     .map(|&(_, u_name, ascii_char)| {
-        let span = make_span(reader.pos, reader.next_pos);
+        let span = Span { lo: reader.pos, hi: reader.next_pos, ctxt: NO_EXPANSION };
         match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
             Some(&(ascii_char, ascii_name)) => {
                 let msg =
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index e188bcaf105f2..b5d0a46de4926 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -12,7 +12,7 @@
 
 use ast::{self, CrateConfig};
 use codemap::CodeMap;
-use syntax_pos::{self, Span, FileMap};
+use syntax_pos::{self, Span, FileMap, NO_EXPANSION};
 use errors::{Handler, ColorConfig, DiagnosticBuilder};
 use feature_gate::UnstableFeatures;
 use parse::parser::Parser;
@@ -178,7 +178,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc<FileMap>, ) -> Par
     let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap));
 
     if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP {
-        parser.span = syntax_pos::mk_sp(end_pos, end_pos);
+        parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION };
     }
 
     parser
@@ -665,7 +665,7 @@ mod tests {
 
     // produce a syntax_pos::span
     fn sp(a: u32, b: u32) -> Span {
-        Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION}
+        Span {lo: BytePos(a), hi: BytePos(b), ctxt: NO_EXPANSION}
     }
 
     fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ef7b79bccfa01..4556061b36df7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -40,8 +40,8 @@ use ast::{Visibility, WhereClause};
 use ast::{BinOpKind, UnOp};
 use ast::RangeEnd;
 use {ast, attr};
-use codemap::{self, CodeMap, Spanned, spanned, respan};
-use syntax_pos::{self, Span, BytePos, mk_sp};
+use codemap::{self, CodeMap, Spanned, respan};
+use syntax_pos::{self, Span, BytePos};
 use errors::{self, DiagnosticBuilder};
 use parse::{self, classify, token};
 use parse::common::SeqSep;
@@ -108,13 +108,13 @@ macro_rules! maybe_whole_expr {
                     $p.bump();
                     let span = $p.span;
                     let kind = ExprKind::Path(None, (*path).clone());
-                    return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new()));
+                    return Ok($p.mk_expr(span, kind, ThinVec::new()));
                 }
                 token::NtBlock(ref block) => {
                     $p.bump();
                     let span = $p.span;
                     let kind = ExprKind::Block((*block).clone());
-                    return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new()));
+                    return Ok($p.mk_expr(span, kind, ThinVec::new()));
                 }
                 _ => {},
             };
@@ -731,7 +731,7 @@ impl<'a> Parser<'a> {
             token::AndAnd => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::BinOp(token::And), lo, span.hi))
+                Ok(self.bump_with(token::BinOp(token::And), Span { lo: lo, ..span }))
             }
             _ => self.unexpected()
         }
@@ -765,7 +765,7 @@ impl<'a> Parser<'a> {
             token::BinOp(token::Shl) => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                self.bump_with(token::Lt, lo, span.hi);
+                self.bump_with(token::Lt, Span { lo: lo, ..span });
                 true
             }
             _ => false,
@@ -793,17 +793,17 @@ impl<'a> Parser<'a> {
             token::BinOp(token::Shr) => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::Gt, lo, span.hi))
+                Ok(self.bump_with(token::Gt, Span { lo: lo, ..span }))
             }
             token::BinOpEq(token::Shr) => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::Ge, lo, span.hi))
+                Ok(self.bump_with(token::Ge, Span { lo: lo, ..span }))
             }
             token::Ge => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::Eq, lo, span.hi))
+                Ok(self.bump_with(token::Eq, Span { lo: lo, ..span }))
             }
             _ => self.unexpected()
         }
@@ -997,12 +997,12 @@ impl<'a> Parser<'a> {
                            -> PResult<'a, Spanned<Vec<T>>> where
         F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
     {
-        let lo = self.span.lo;
+        let lo = self.span;
         self.expect(bra)?;
         let result = self.parse_seq_to_before_end(ket, sep, f);
-        let hi = self.span.hi;
+        let hi = self.span;
         self.bump();
-        Ok(spanned(lo, hi, result))
+        Ok(respan(lo.to(hi), result))
     }
 
     /// Advance the parser by one token
@@ -1033,16 +1033,13 @@ impl<'a> Parser<'a> {
 
     /// Advance the parser using provided token as a next one. Use this when
     /// consuming a part of a token. For example a single `<` from `<<`.
-    pub fn bump_with(&mut self,
-                     next: token::Token,
-                     lo: BytePos,
-                     hi: BytePos) {
-        self.prev_span = mk_sp(self.span.lo, lo);
+    pub fn bump_with(&mut self, next: token::Token, span: Span) {
+        self.prev_span = Span { hi: span.lo, ..self.span };
         // It would be incorrect to record the kind of the current token, but
         // fortunately for tokens currently using `bump_with`, the
         // prev_token_kind will be of no use anyway.
         self.prev_token_kind = PrevTokenKind::Other;
-        self.span = mk_sp(lo, hi);
+        self.span = span;
         self.token = next;
         self.expected_tokens.clear();
     }
@@ -1173,7 +1170,7 @@ impl<'a> Parser<'a> {
     pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
         maybe_whole!(self, NtTraitItem, |x| x);
         let mut attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
 
         let (name, node) = if self.eat_keyword(keywords::Type) {
             let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
@@ -1197,7 +1194,7 @@ impl<'a> Parser<'a> {
         } else if self.token.is_path_start() {
             // trait item macro.
             // code copied from parse_macro_use_or_failure... abstraction!
-            let lo = self.span.lo;
+            let lo = self.span;
             let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
@@ -1207,7 +1204,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?
             }
 
-            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
+            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
         } else {
             let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
@@ -1277,7 +1274,7 @@ impl<'a> Parser<'a> {
             ident: name,
             attrs: attrs,
             node: node,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
         })
     }
 
@@ -1298,8 +1295,7 @@ impl<'a> Parser<'a> {
         if self.eat(&token::RArrow) {
             Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?))
         } else {
-            let pos = self.span.lo;
-            Ok(FunctionRetTy::Default(mk_sp(pos, pos)))
+            Ok(FunctionRetTy::Default(Span { hi: self.span.lo, ..self.span }))
         }
     }
 
@@ -1320,7 +1316,7 @@ impl<'a> Parser<'a> {
     fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
         maybe_whole!(self, NtTy, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let node = if self.eat(&token::OpenDelim(token::Paren)) {
             // `(TYPE)` is a parenthesized type.
             // `(TYPE,)` is a tuple with a single field of type TYPE.
@@ -1344,7 +1340,7 @@ impl<'a> Parser<'a> {
                     TyKind::Path(None, ref path)
                             if allow_plus && self.token == token::BinOp(token::Plus) => {
                         self.bump(); // `+`
-                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo, self.prev_span.hi);
+                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span));
                         let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)];
                         bounds.append(&mut self.parse_ty_param_bounds()?);
                         TyKind::TraitObject(bounds)
@@ -1394,13 +1390,13 @@ impl<'a> Parser<'a> {
             if self.eat(&token::Not) {
                 // Macro invocation in type position
                 let (_, tts) = self.expect_delimited_token_tree()?;
-                TyKind::Mac(spanned(lo, self.span.hi, Mac_ { path: path, tts: tts }))
+                TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
             } else {
                 // Just a type path or bound list (trait object type) starting with a trait.
                 //   `Type`
                 //   `Trait1 + Trait2 + 'a`
                 if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo, self.prev_span.hi);
+                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span));
                     let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
                     bounds.append(&mut self.parse_ty_param_bounds()?);
                     TyKind::TraitObject(bounds)
@@ -1415,13 +1411,13 @@ impl<'a> Parser<'a> {
             // Function pointer type or bound list (trait object type) starting with a poly-trait.
             //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
             //   `for<'lt> Trait1<'lt> + Trait2 + 'a`
-            let lo = self.span.lo;
+            let lo = self.span;
             let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
             if self.token_is_bare_fn_keyword() {
                 self.parse_ty_bare_fn(lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi);
+                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
                 let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
                 if allow_plus && self.eat(&token::BinOp(token::Plus)) {
                     bounds.append(&mut self.parse_ty_param_bounds()?)
@@ -1440,7 +1436,7 @@ impl<'a> Parser<'a> {
             return Err(self.fatal(&msg));
         };
 
-        let span = mk_sp(lo, self.prev_span.hi);
+        let span = lo.to(self.prev_span);
         let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID };
 
         // Try to recover from use of `+` with incorrect priority.
@@ -1457,7 +1453,7 @@ impl<'a> Parser<'a> {
 
         self.bump(); // `+`
         let bounds = self.parse_ty_param_bounds()?;
-        let sum_span = mk_sp(ty.span.lo, self.prev_span.hi);
+        let sum_span = ty.span.to(self.prev_span);
 
         let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178,
             "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty));
@@ -1577,7 +1573,7 @@ impl<'a> Parser<'a> {
             P(Ty {
                 id: ast::DUMMY_NODE_ID,
                 node: TyKind::Infer,
-                span: mk_sp(self.span.lo, self.span.hi),
+                span: self.span,
             })
         };
         Ok(Arg {
@@ -1625,7 +1621,7 @@ impl<'a> Parser<'a> {
 
     /// Matches lit = true | false | token_lit
     pub fn parse_lit(&mut self) -> PResult<'a, Lit> {
-        let lo = self.span.lo;
+        let lo = self.span;
         let lit = if self.eat_keyword(keywords::True) {
             LitKind::Bool(true)
         } else if self.eat_keyword(keywords::False) {
@@ -1634,22 +1630,22 @@ impl<'a> Parser<'a> {
             let lit = self.parse_lit_token()?;
             lit
         };
-        Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) })
+        Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) })
     }
 
     /// matches '-' lit | lit
     pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
-        let minus_lo = self.span.lo;
+        let minus_lo = self.span;
         let minus_present = self.eat(&token::BinOp(token::Minus));
-        let lo = self.span.lo;
+        let lo = self.span;
         let literal = P(self.parse_lit()?);
-        let hi = self.prev_span.hi;
-        let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new());
+        let hi = self.prev_span;
+        let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new());
 
         if minus_present {
-            let minus_hi = self.prev_span.hi;
+            let minus_hi = self.prev_span;
             let unary = self.mk_unary(UnOp::Neg, expr);
-            Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new()))
+            Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new()))
         } else {
             Ok(expr)
         }
@@ -1726,7 +1722,7 @@ impl<'a> Parser<'a> {
     pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
         maybe_whole!(self, NtPath, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let is_global = self.eat(&token::ModSep);
 
         // Parse any number of segments and bound sets. A segment is an
@@ -1750,7 +1746,7 @@ impl<'a> Parser<'a> {
 
         // Assemble the span.
         // FIXME(#39450) This is bogus if part of the path is macro generated.
-        let span = mk_sp(lo, self.prev_span.hi);
+        let span = lo.to(self.prev_span);
 
         // Assemble the result.
         Ok(ast::Path {
@@ -1791,7 +1787,7 @@ impl<'a> Parser<'a> {
                     bindings: bindings,
                 }.into()
             } else if self.eat(&token::OpenDelim(token::Paren)) {
-                let lo = self.prev_span.lo;
+                let lo = self.prev_span;
 
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
@@ -1804,10 +1800,10 @@ impl<'a> Parser<'a> {
                     None
                 };
 
-                let hi = self.prev_span.hi;
+                let hi = self.prev_span;
 
                 Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData {
-                    span: mk_sp(lo, hi),
+                    span: lo.to(hi),
                     inputs: inputs,
                     output: output_ty,
                 })))
@@ -1928,38 +1924,37 @@ impl<'a> Parser<'a> {
     /// Parse ident (COLON expr)?
     pub fn parse_field(&mut self) -> PResult<'a, Field> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
         let hi;
 
         // Check if a colon exists one ahead. This means we're parsing a fieldname.
         let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
             let fieldname = self.parse_field_name()?;
             self.bump();
-            hi = self.prev_span.hi;
+            hi = self.prev_span;
             (fieldname, self.parse_expr()?, false)
         } else {
             let fieldname = self.parse_ident()?;
-            hi = self.prev_span.hi;
+            hi = self.prev_span;
 
             // Mimic `x: x` for the `x` field shorthand.
-            let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname);
-            (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true)
+            let path = ast::Path::from_ident(lo.to(hi), fieldname);
+            (fieldname, self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()), true)
         };
         Ok(ast::Field {
-            ident: spanned(lo, hi, fieldname),
-            span: mk_sp(lo, expr.span.hi),
+            ident: respan(lo.to(hi), fieldname),
+            span: lo.to(expr.span),
             expr: expr,
             is_shorthand: is_shorthand,
             attrs: attrs.into(),
         })
     }
 
-    pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec<Attribute>)
-                   -> P<Expr> {
+    pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr {
             id: ast::DUMMY_NODE_ID,
             node: node,
-            span: mk_sp(lo, hi),
+            span: span,
             attrs: attrs.into(),
         })
     }
@@ -2013,12 +2008,11 @@ impl<'a> Parser<'a> {
         ExprKind::AssignOp(binop, lhs, rhs)
     }
 
-    pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos,
-                       m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
+    pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr {
             id: ast::DUMMY_NODE_ID,
-            node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}),
-            span: mk_sp(lo, hi),
+            node: ExprKind::Mac(codemap::Spanned {node: m, span: span}),
+            span: span,
             attrs: attrs,
         })
     }
@@ -2065,8 +2059,8 @@ impl<'a> Parser<'a> {
         // attributes by giving them a empty "already parsed" list.
         let mut attrs = ThinVec::new();
 
-        let lo = self.span.lo;
-        let mut hi = self.span.hi;
+        let lo = self.span;
+        let mut hi = self.span;
 
         let ex: ExprKind;
 
@@ -2095,18 +2089,19 @@ impl<'a> Parser<'a> {
                 }
                 self.bump();
 
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
+                let span = lo.to(hi);
                 return if es.len() == 1 && !trailing_comma {
-                    Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
+                    Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
                 } else {
-                    Ok(self.mk_expr(lo, hi, ExprKind::Tup(es), attrs))
+                    Ok(self.mk_expr(span, ExprKind::Tup(es), attrs))
                 }
             },
             token::OpenDelim(token::Brace) => {
                 return self.parse_block_expr(lo, BlockCheckMode::Default, attrs);
             },
             token::BinOp(token::Or) |  token::OrOr => {
-                let lo = self.span.lo;
+                let lo = self.span;
                 return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs);
             },
             token::OpenDelim(token::Bracket) => {
@@ -2144,34 +2139,34 @@ impl<'a> Parser<'a> {
                         ex = ExprKind::Array(vec![first_expr]);
                     }
                 }
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
             }
             _ => {
                 if self.eat_lt() {
                     let (qself, path) =
                         self.parse_qualified_path(PathStyle::Expr)?;
-                    hi = path.span.hi;
-                    return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs));
+                    hi = path.span;
+                    return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
                 }
                 if self.eat_keyword(keywords::Move) {
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_lambda_expr(lo, CaptureBy::Value, attrs);
                 }
                 if self.eat_keyword(keywords::If) {
                     return self.parse_if_expr(attrs);
                 }
                 if self.eat_keyword(keywords::For) {
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_for_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::While) {
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_while_expr(None, lo, attrs);
                 }
                 if self.token.is_lifetime() {
                     let label = Spanned { node: self.get_label(),
                                           span: self.span };
-                    let lo = self.span.lo;
+                    let lo = self.span;
                     self.bump();
                     self.expect(&token::Colon)?;
                     if self.eat_keyword(keywords::While) {
@@ -2186,7 +2181,7 @@ impl<'a> Parser<'a> {
                     return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
                 }
                 if self.eat_keyword(keywords::Loop) {
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_loop_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::Continue) {
@@ -2200,8 +2195,8 @@ impl<'a> Parser<'a> {
                     } else {
                         ExprKind::Continue(None)
                     };
-                    let hi = self.prev_span.hi;
-                    return Ok(self.mk_expr(lo, hi, ex, attrs));
+                    let hi = self.prev_span;
+                    return Ok(self.mk_expr(lo.to(hi), ex, attrs));
                 }
                 if self.eat_keyword(keywords::Match) {
                     return self.parse_match_expr(attrs);
@@ -2215,13 +2210,13 @@ impl<'a> Parser<'a> {
                 if self.is_catch_expr() {
                     assert!(self.eat_keyword(keywords::Do));
                     assert!(self.eat_keyword(keywords::Catch));
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_catch_expr(lo, attrs);
                 }
                 if self.eat_keyword(keywords::Return) {
                     if self.token.can_begin_expr() {
                         let e = self.parse_expr()?;
-                        hi = e.span.hi;
+                        hi = e.span;
                         ex = ExprKind::Ret(Some(e));
                     } else {
                         ex = ExprKind::Ret(None);
@@ -2246,7 +2241,7 @@ impl<'a> Parser<'a> {
                         None
                     };
                     ex = ExprKind::Break(lt, e);
-                    hi = self.prev_span.hi;
+                    hi = self.prev_span;
                 } else if self.token.is_keyword(keywords::Let) {
                     // Catch this syntax error here, instead of in `check_strict_keywords`, so
                     // that we can explicitly mention that let is not to be used as an expression
@@ -2260,8 +2255,8 @@ impl<'a> Parser<'a> {
                     if self.eat(&token::Not) {
                         // MACRO INVOCATION expression
                         let (_, tts) = self.expect_delimited_token_tree()?;
-                        let hi = self.prev_span.hi;
-                        return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
+                        let hi = self.prev_span;
+                        return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs));
                     }
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
@@ -2274,12 +2269,12 @@ impl<'a> Parser<'a> {
                         }
                     }
 
-                    hi = pth.span.hi;
+                    hi = pth.span;
                     ex = ExprKind::Path(None, pth);
                 } else {
                     match self.parse_lit() {
                         Ok(lit) => {
-                            hi = lit.span.hi;
+                            hi = lit.span;
                             ex = ExprKind::Lit(P(lit));
                         }
                         Err(mut err) => {
@@ -2293,10 +2288,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        return Ok(self.mk_expr(lo, hi, ex, attrs));
+        return Ok(self.mk_expr(lo.to(hi), ex, attrs));
     }
 
-    fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>)
+    fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
                          -> PResult<'a, P<Expr>> {
         self.bump();
         let mut fields = Vec::new();
@@ -2338,9 +2333,9 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.span.hi;
+        let span = lo.to(self.span);
         self.expect(&token::CloseDelim(token::Brace))?;
-        return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs));
+        return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs));
     }
 
     fn parse_or_use_outer_attributes(&mut self,
@@ -2354,7 +2349,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a block or unsafe block
-    pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode,
+    pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode,
                             outer_attrs: ThinVec<Attribute>)
                             -> PResult<'a, P<Expr>> {
 
@@ -2364,7 +2359,7 @@ impl<'a> Parser<'a> {
         attrs.extend(self.parse_inner_attributes()?);
 
         let blk = self.parse_block_tail(lo, blk_mode)?;
-        return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs));
+        return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs));
     }
 
     /// parse a.b or a(13) or a[4] or just a
@@ -2375,12 +2370,12 @@ impl<'a> Parser<'a> {
 
         let b = self.parse_bottom_expr();
         let (span, b) = self.interpolated_or_expr_span(b)?;
-        self.parse_dot_or_call_expr_with(b, span.lo, attrs)
+        self.parse_dot_or_call_expr_with(b, span, attrs)
     }
 
     pub fn parse_dot_or_call_expr_with(&mut self,
                                        e0: P<Expr>,
-                                       lo: BytePos,
+                                       lo: Span,
                                        mut attrs: ThinVec<Attribute>)
                                        -> PResult<'a, P<Expr>> {
         // Stitch the list of outer attributes onto the return value.
@@ -2411,11 +2406,7 @@ impl<'a> Parser<'a> {
 
     // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue
     // parsing into an expression.
-    fn parse_dot_suffix(&mut self,
-                        ident: Ident,
-                        ident_span: Span,
-                        self_value: P<Expr>,
-                        lo: BytePos)
+    fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span)
                         -> PResult<'a, P<Expr>> {
         let (_, tys, bindings) = if self.eat(&token::ModSep) {
             self.expect_lt()?;
@@ -2440,12 +2431,12 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                let hi = self.prev_span.hi;
+                let hi = self.prev_span;
 
                 es.insert(0, self_value);
-                let id = spanned(ident_span.lo, ident_span.hi, ident);
+                let id = respan(ident_span.to(ident_span), ident);
                 let nd = self.mk_method_call(id, tys, es);
-                self.mk_expr(lo, hi, nd, ThinVec::new())
+                self.mk_expr(lo.to(hi), nd, ThinVec::new())
             }
             // Field access.
             _ => {
@@ -2456,32 +2447,30 @@ impl<'a> Parser<'a> {
                                    have type parameters");
                 }
 
-                let id = spanned(ident_span.lo, ident_span.hi, ident);
+                let id = respan(ident_span.to(ident_span), ident);
                 let field = self.mk_field(self_value, id);
-                self.mk_expr(lo, ident_span.hi, field, ThinVec::new())
+                self.mk_expr(lo.to(ident_span), field, ThinVec::new())
             }
         })
     }
 
-    fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<'a, P<Expr>> {
+    fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
         let mut e = e0;
         let mut hi;
         loop {
             // expr?
             while self.eat(&token::Question) {
-                let hi = self.prev_span.hi;
-                e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new());
+                let hi = self.prev_span;
+                e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new());
             }
 
             // expr.f
             if self.eat(&token::Dot) {
                 match self.token {
                   token::Ident(i) => {
-                    let dot_pos = self.prev_span.hi;
-                    hi = self.span.hi;
+                    let ident_span = self.span;
                     self.bump();
-
-                    e = self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e, lo)?;
+                    e = self.parse_dot_suffix(i, ident_span, e, lo)?;
                   }
                   token::Literal(token::Integer(n), suf) => {
                     let sp = self.span;
@@ -2489,16 +2478,16 @@ impl<'a> Parser<'a> {
                     // A tuple index may not have a suffix
                     self.expect_no_suffix(sp, "tuple index", suf);
 
-                    let dot = self.prev_span.hi;
-                    hi = self.span.hi;
+                    let dot_span = self.prev_span;
+                    hi = self.span;
                     self.bump();
 
                     let index = n.as_str().parse::<usize>().ok();
                     match index {
                         Some(n) => {
-                            let id = spanned(dot, hi, n);
+                            let id = respan(dot_span.to(hi), n);
                             let field = self.mk_tup_field(e, id);
-                            e = self.mk_expr(lo, hi, field, ThinVec::new());
+                            e = self.mk_expr(lo.to(hi), field, ThinVec::new());
                         }
                         None => {
                             let prev_span = self.prev_span;
@@ -2541,10 +2530,8 @@ impl<'a> Parser<'a> {
                     let actual = self.this_token_to_string();
                     self.span_err(self.span, &format!("unexpected token: `{}`", actual));
 
-                    let dot_pos = self.prev_span.hi;
-                    e = self.parse_dot_suffix(keywords::Invalid.ident(),
-                                              mk_sp(dot_pos, dot_pos),
-                                              e, lo)?;
+                    let dot_span = self.prev_span;
+                    e = self.parse_dot_suffix(keywords::Invalid.ident(), dot_span, e, lo)?;
                   }
                 }
                 continue;
@@ -2559,10 +2546,10 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
 
                 let nd = self.mk_call(e, es);
-                e = self.mk_expr(lo, hi, nd, ThinVec::new());
+                e = self.mk_expr(lo.to(hi), nd, ThinVec::new());
               }
 
               // expr[...]
@@ -2570,10 +2557,10 @@ impl<'a> Parser<'a> {
               token::OpenDelim(token::Bracket) => {
                 self.bump();
                 let ix = self.parse_expr()?;
-                hi = self.span.hi;
+                hi = self.span;
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let index = self.mk_index(e, ix);
-                e = self.mk_expr(lo, hi, index, ThinVec::new())
+                e = self.mk_expr(lo.to(hi), index, ThinVec::new())
               }
               _ => return Ok(e)
             }
@@ -2635,38 +2622,33 @@ impl<'a> Parser<'a> {
                              already_parsed_attrs: Option<ThinVec<Attribute>>)
                              -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
-        let lo = self.span.lo;
-        let hi;
+        let lo = self.span;
         // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr()
-        let ex = match self.token {
+        let (hi, ex) = match self.token {
             token::Not => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                self.mk_unary(UnOp::Not, e)
+                (span, self.mk_unary(UnOp::Not, e))
             }
             token::BinOp(token::Minus) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                self.mk_unary(UnOp::Neg, e)
+                (span, self.mk_unary(UnOp::Neg, e))
             }
             token::BinOp(token::Star) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                self.mk_unary(UnOp::Deref, e)
+                (span, self.mk_unary(UnOp::Deref, e))
             }
             token::BinOp(token::And) | token::AndAnd => {
                 self.expect_and()?;
                 let m = self.parse_mutability();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                ExprKind::AddrOf(m, e)
+                (span, ExprKind::AddrOf(m, e))
             }
             token::Ident(..) if self.token.is_keyword(keywords::In) => {
                 self.bump();
@@ -2676,20 +2658,18 @@ impl<'a> Parser<'a> {
                 )?;
                 let blk = self.parse_block()?;
                 let span = blk.span;
-                hi = span.hi;
-                let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new());
-                ExprKind::InPlace(place, blk_expr)
+                let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new());
+                (span, ExprKind::InPlace(place, blk_expr))
             }
             token::Ident(..) if self.token.is_keyword(keywords::Box) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                ExprKind::Box(e)
+                (span, ExprKind::Box(e))
             }
             _ => return self.parse_dot_or_call_expr(Some(attrs))
         };
-        return Ok(self.mk_expr(lo, hi, ex, attrs));
+        return Ok(self.mk_expr(lo.to(hi), ex, attrs));
     }
 
     /// Parse an associative expression
@@ -2750,13 +2730,11 @@ impl<'a> Parser<'a> {
             // Special cases:
             if op == AssocOp::As {
                 let rhs = self.parse_ty_no_plus()?;
-                let (lo, hi) = (lhs_span.lo, rhs.span.hi);
-                lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new());
+                lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new());
                 continue
             } else if op == AssocOp::Colon {
                 let rhs = self.parse_ty_no_plus()?;
-                let (lo, hi) = (lhs_span.lo, rhs.span.hi);
-                lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new());
+                lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Type(lhs, rhs), ThinVec::new());
                 continue
             } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot {
                 // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
@@ -2782,7 +2760,7 @@ impl<'a> Parser<'a> {
                 };
 
                 let r = try!(self.mk_range(Some(lhs), rhs, limits));
-                lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new());
+                lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new());
                 break
             }
 
@@ -2809,7 +2787,7 @@ impl<'a> Parser<'a> {
                 }),
             }?;
 
-            let (lo, hi) = (lhs_span.lo, rhs.span.hi);
+            let span = lhs_span.to(rhs.span);
             lhs = match op {
                 AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide |
                 AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor |
@@ -2818,12 +2796,12 @@ impl<'a> Parser<'a> {
                 AssocOp::Greater | AssocOp::GreaterEqual => {
                     let ast_op = op.to_ast_binop().unwrap();
                     let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs);
-                    self.mk_expr(lo, hi, binary, ThinVec::new())
+                    self.mk_expr(span, binary, ThinVec::new())
                 }
                 AssocOp::Assign =>
-                    self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()),
+                    self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
                 AssocOp::Inplace =>
-                    self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
+                    self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
                 AssocOp::AssignOp(k) => {
                     let aop = match k {
                         token::Plus =>    BinOpKind::Add,
@@ -2838,7 +2816,7 @@ impl<'a> Parser<'a> {
                         token::Shr =>     BinOpKind::Shr,
                     };
                     let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
-                    self.mk_expr(lo, hi, aopexpr, ThinVec::new())
+                    self.mk_expr(span, aopexpr, ThinVec::new())
                 }
                 AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => {
                     self.bug("As, Colon, DotDot or DotDotDot branch reached")
@@ -2858,7 +2836,7 @@ impl<'a> Parser<'a> {
         match lhs.node {
             ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
                 // respan to include both operators
-                let op_span = mk_sp(op.span.lo, self.span.hi);
+                let op_span = op.span.to(self.span);
                 let mut err = self.diagnostic().struct_span_err(op_span,
                     "chained comparison operators require parentheses");
                 if op.node == BinOpKind::Lt &&
@@ -2881,8 +2859,8 @@ impl<'a> Parser<'a> {
         debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot);
         let tok = self.token.clone();
         let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
-        let lo = self.span.lo;
-        let mut hi = self.span.hi;
+        let lo = self.span;
+        let mut hi = self.span;
         self.bump();
         let opt_end = if self.is_at_start_of_range_notation_rhs() {
             // RHS must be parsed with more associativity than the dots.
@@ -2890,7 +2868,7 @@ impl<'a> Parser<'a> {
             Some(self.parse_assoc_expr_with(next_prec,
                                             LhsExpr::NotYetParsed)
                 .map(|x|{
-                    hi = x.span.hi;
+                    hi = x.span;
                     x
                 })?)
          } else {
@@ -2905,7 +2883,7 @@ impl<'a> Parser<'a> {
         let r = try!(self.mk_range(None,
                                    opt_end,
                                    limits));
-        Ok(self.mk_expr(lo, hi, r, attrs))
+        Ok(self.mk_expr(lo.to(hi), r, attrs))
     }
 
     fn is_at_start_of_range_notation_rhs(&self) -> bool {
@@ -2925,23 +2903,23 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Let) {
             return self.parse_if_let_expr(attrs);
         }
-        let lo = self.prev_span.lo;
+        let lo = self.prev_span;
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let mut els: Option<P<Expr>> = None;
-        let mut hi = thn.span.hi;
+        let mut hi = thn.span;
         if self.eat_keyword(keywords::Else) {
             let elexpr = self.parse_else_expr()?;
-            hi = elexpr.span.hi;
+            hi = elexpr.span;
             els = Some(elexpr);
         }
-        Ok(self.mk_expr(lo, hi, ExprKind::If(cond, thn, els), attrs))
+        Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
     }
 
     /// Parse an 'if let' expression ('if' token already eaten)
     pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>> {
-        let lo = self.prev_span.lo;
+        let lo = self.prev_span;
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
@@ -2949,36 +2927,35 @@ impl<'a> Parser<'a> {
         let thn = self.parse_block()?;
         let (hi, els) = if self.eat_keyword(keywords::Else) {
             let expr = self.parse_else_expr()?;
-            (expr.span.hi, Some(expr))
+            (expr.span, Some(expr))
         } else {
-            (thn.span.hi, None)
+            (thn.span, None)
         };
-        Ok(self.mk_expr(lo, hi, ExprKind::IfLet(pat, expr, thn, els), attrs))
+        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs))
     }
 
     // `move |args| expr`
     pub fn parse_lambda_expr(&mut self,
-                             lo: BytePos,
+                             lo: Span,
                              capture_clause: CaptureBy,
                              attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>>
     {
         let decl = self.parse_fn_block_decl()?;
-        let decl_hi = self.prev_span.hi;
+        let decl_hi = self.prev_span;
         let body = match decl.output {
             FunctionRetTy::Default(_) => self.parse_expr()?,
             _ => {
                 // If an explicit return type is given, require a
                 // block to appear (RFC 968).
-                let body_lo = self.span.lo;
+                let body_lo = self.span;
                 self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())?
             }
         };
 
         Ok(self.mk_expr(
-            lo,
-            body.span.hi,
-            ExprKind::Closure(capture_clause, decl, body, mk_sp(lo, decl_hi)),
+            lo.to(body.span),
+            ExprKind::Closure(capture_clause, decl, body, lo.to(decl_hi)),
             attrs))
     }
 
@@ -2988,13 +2965,13 @@ impl<'a> Parser<'a> {
             return self.parse_if_expr(ThinVec::new());
         } else {
             let blk = self.parse_block()?;
-            return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new()));
+            return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new()));
         }
     }
 
     /// Parse a 'for' .. 'in' expression ('for' token already eaten)
     pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                          span_lo: BytePos,
+                          span_lo: Span,
                           mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
 
@@ -3004,16 +2981,13 @@ impl<'a> Parser<'a> {
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
 
-        let hi = self.prev_span.hi;
-
-        Ok(self.mk_expr(span_lo, hi,
-                        ExprKind::ForLoop(pat, expr, loop_block, opt_ident),
-                        attrs))
+        let hi = self.prev_span;
+        Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs))
     }
 
     /// Parse a 'while' or 'while let' expression ('while' token already eaten)
     pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                            span_lo: BytePos,
+                            span_lo: Span,
                             mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         if self.token.is_keyword(keywords::Let) {
             return self.parse_while_let_expr(opt_ident, span_lo, attrs);
@@ -3021,14 +2995,13 @@ impl<'a> Parser<'a> {
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident),
-                               attrs));
+        let span = span_lo.to(body.span);
+        return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs));
     }
 
     /// Parse a 'while let' expression ('while' token already eaten)
     pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                                span_lo: BytePos,
+                                span_lo: Span,
                                 mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
@@ -3036,34 +3009,33 @@ impl<'a> Parser<'a> {
         let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
+        let span = span_lo.to(body.span);
+        return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
     }
 
     // parse `loop {...}`, `loop` token already eaten
     pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                           span_lo: BytePos,
+                           span_lo: Span,
                            mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs))
+        let span = span_lo.to(body.span);
+        Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs))
     }
 
     /// Parse a `do catch {...}` expression (`do catch` token already eaten)
-    pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec<Attribute>)
+    pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
         -> PResult<'a, P<Expr>>
     {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs))
+        Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
     }
 
     // `match` token already eaten
     fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_span;
-        let lo = self.prev_span.lo;
+        let lo = self.prev_span;
         let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
@@ -3082,17 +3054,17 @@ impl<'a> Parser<'a> {
                     // Recover by skipping to the end of the block.
                     e.emit();
                     self.recover_stmt();
-                    let hi = self.span.hi;
+                    let span = lo.to(self.span);
                     if self.token == token::CloseDelim(token::Brace) {
                         self.bump();
                     }
-                    return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs));
+                    return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs));
                 }
             }
         }
-        let hi = self.span.hi;
+        let hi = self.span;
         self.bump();
-        return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs));
+        return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs));
     }
 
     pub fn parse_arm(&mut self) -> PResult<'a, Arm> {
@@ -3266,7 +3238,7 @@ impl<'a> Parser<'a> {
             }
 
             let attrs = self.parse_outer_attributes()?;
-            let lo = self.span.lo;
+            let lo = self.span;
             let hi;
 
             if self.check(&token::DotDot) {
@@ -3286,16 +3258,16 @@ impl<'a> Parser<'a> {
                 let fieldname = self.parse_field_name()?;
                 self.bump();
                 let pat = self.parse_pat()?;
-                hi = pat.span.hi;
+                hi = pat.span;
                 (pat, fieldname, false)
             } else {
                 // Parsing a pattern of the form "(box) (ref) (mut) fieldname"
                 let is_box = self.eat_keyword(keywords::Box);
-                let boxed_span_lo = self.span.lo;
+                let boxed_span = self.span;
                 let is_ref = self.eat_keyword(keywords::Ref);
                 let is_mut = self.eat_keyword(keywords::Mut);
                 let fieldname = self.parse_ident()?;
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
 
                 let bind_type = match (is_ref, is_mut) {
                     (true, true) => BindingMode::ByRef(Mutability::Mutable),
@@ -3307,14 +3279,14 @@ impl<'a> Parser<'a> {
                 let fieldpat = P(ast::Pat{
                     id: ast::DUMMY_NODE_ID,
                     node: PatKind::Ident(bind_type, fieldpath, None),
-                    span: mk_sp(boxed_span_lo, hi),
+                    span: boxed_span.to(hi),
                 });
 
                 let subpat = if is_box {
                     P(ast::Pat{
                         id: ast::DUMMY_NODE_ID,
                         node: PatKind::Box(fieldpat),
-                        span: mk_sp(lo, hi),
+                        span: lo.to(hi),
                     })
                 } else {
                     fieldpat
@@ -3322,7 +3294,7 @@ impl<'a> Parser<'a> {
                 (subpat, fieldname, true)
             };
 
-            fields.push(codemap::Spanned { span: mk_sp(lo, hi),
+            fields.push(codemap::Spanned { span: lo.to(hi),
                                            node: ast::FieldPat {
                                                ident: fieldname,
                                                pat: subpat,
@@ -3336,7 +3308,7 @@ impl<'a> Parser<'a> {
 
     fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
         if self.token.is_path_start() {
-            let lo = self.span.lo;
+            let lo = self.span;
             let (qself, path) = if self.eat_lt() {
                 // Parse a qualified path
                 let (qself, path) =
@@ -3346,8 +3318,8 @@ impl<'a> Parser<'a> {
                 // Parse an unqualified path
                 (None, self.parse_path(PathStyle::Expr)?)
             };
-            let hi = self.prev_span.hi;
-            Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()))
+            let hi = self.prev_span;
+            Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new()))
         } else {
             self.parse_pat_literal_maybe_minus()
         }
@@ -3373,7 +3345,7 @@ impl<'a> Parser<'a> {
     pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
         maybe_whole!(self, NtPat, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let pat;
         match self.token {
             token::Underscore => {
@@ -3439,7 +3411,7 @@ impl<'a> Parser<'a> {
                         // Parse macro invocation
                         self.bump();
                         let (_, tts) = self.expect_delimited_token_tree()?;
-                        let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
+                        let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts });
                         pat = PatKind::Mac(mac);
                     }
                     token::DotDotDot | token::DotDot => {
@@ -3449,9 +3421,8 @@ impl<'a> Parser<'a> {
                             _ => panic!("can only parse `..` or `...` for ranges (checked above)"),
                         };
                         // Parse range
-                        let hi = self.prev_span.hi;
-                        let begin =
-                              self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
+                        let span = lo.to(self.prev_span);
+                        let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
                         self.bump();
                         let end = self.parse_pat_range_end()?;
                         pat = PatKind::Range(begin, end, end_kind);
@@ -3505,11 +3476,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.prev_span.hi;
         Ok(P(ast::Pat {
             id: ast::DUMMY_NODE_ID,
             node: pat,
-            span: mk_sp(lo, hi),
+            span: lo.to(self.prev_span),
         }))
     }
 
@@ -3545,7 +3515,7 @@ impl<'a> Parser<'a> {
 
     /// Parse a local variable declaration
     fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
-        let lo = self.span.lo;
+        let lo = self.span;
         let pat = self.parse_pat()?;
 
         let mut ty = None;
@@ -3558,14 +3528,14 @@ impl<'a> Parser<'a> {
             pat: pat,
             init: init,
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
             attrs: attrs,
         }))
     }
 
     /// Parse a structure field
     fn parse_name_and_ty(&mut self,
-                         lo: BytePos,
+                         lo: Span,
                          vis: Visibility,
                          attrs: Vec<Attribute>)
                          -> PResult<'a, StructField> {
@@ -3573,7 +3543,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
         Ok(StructField {
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
             ident: Some(name),
             vis: vis,
             id: ast::DUMMY_NODE_ID,
@@ -3683,7 +3653,7 @@ impl<'a> Parser<'a> {
 
     fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility)
                      -> PResult<'a, Option<P<Item>>> {
-        let lo = self.span.lo;
+        let lo = self.span;
         match self.token {
             token::Ident(ident) if ident.name == "macro_rules" => {
                 if self.look_ahead(1, |t| *t == token::Not) {
@@ -3706,9 +3676,9 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.prev_span.hi;
+        let span = lo.to(self.prev_span);
         let kind = ItemKind::MacroDef(tts);
-        Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned())))
+        Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned())))
     }
 
     fn parse_stmt_without_recovery(&mut self,
@@ -3717,19 +3687,19 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtStmt, |x| Some(x));
 
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
 
         Ok(Some(if self.eat_keyword(keywords::Let) {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
                 node: StmtKind::Local(self.parse_local(attrs.into())?),
-                span: mk_sp(lo, self.prev_span.hi),
+                span: lo.to(self.prev_span),
             }
         } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
                 node: StmtKind::Item(macro_def),
-                span: mk_sp(lo, self.prev_span.hi),
+                span: lo.to(self.prev_span),
             }
         // Starts like a simple path, but not a union item.
         } else if self.token.is_path_start() &&
@@ -3741,8 +3711,8 @@ impl<'a> Parser<'a> {
                 let expr = if self.check(&token::OpenDelim(token::Brace)) {
                     self.parse_struct_expr(lo, pth, ThinVec::new())?
                 } else {
-                    let hi = self.prev_span.hi;
-                    self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new())
+                    let hi = self.prev_span;
+                    self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new())
                 };
 
                 let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| {
@@ -3753,7 +3723,7 @@ impl<'a> Parser<'a> {
                 return Ok(Some(Stmt {
                     id: ast::DUMMY_NODE_ID,
                     node: StmtKind::Expr(expr),
-                    span: mk_sp(lo, self.prev_span.hi),
+                    span: lo.to(self.prev_span),
                 }));
             }
 
@@ -3784,7 +3754,7 @@ impl<'a> Parser<'a> {
             };
 
             let (_, tts) = self.expect_delimited_token_tree()?;
-            let hi = self.prev_span.hi;
+            let hi = self.prev_span;
 
             let style = if delim == token::Brace {
                 MacStmtStyle::Braces
@@ -3793,7 +3763,7 @@ impl<'a> Parser<'a> {
             };
 
             if id.name == keywords::Invalid.name() {
-                let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts });
+                let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts });
                 let node = if delim == token::Brace ||
                               self.token == token::Semi || self.token == token::Eof {
                     StmtKind::Mac(P((mac, style, attrs.into())))
@@ -3813,14 +3783,14 @@ impl<'a> Parser<'a> {
                     self.warn_missing_semicolon();
                     StmtKind::Mac(P((mac, style, attrs.into())))
                 } else {
-                    let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new());
+                    let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new());
                     let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
                     let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
                     StmtKind::Expr(e)
                 };
                 Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, hi),
+                    span: lo.to(hi),
                     node: node,
                 }
             } else {
@@ -3835,13 +3805,14 @@ impl<'a> Parser<'a> {
                                        followed by a semicolon");
                     }
                 }
+                let span = lo.to(hi);
                 Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, hi),
+                    span: span,
                     node: StmtKind::Item({
                         self.mk_item(
-                            lo, hi, id /*id is good here*/,
-                            ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })),
+                            span, id /*id is good here*/,
+                            ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })),
                             Visibility::Inherited,
                             attrs)
                     }),
@@ -3856,7 +3827,7 @@ impl<'a> Parser<'a> {
             match item {
                 Some(i) => Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, i.span.hi),
+                    span: lo.to(i.span),
                     node: StmtKind::Item(i),
                 },
                 None => {
@@ -3887,7 +3858,7 @@ impl<'a> Parser<'a> {
                         Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
                     Stmt {
                         id: ast::DUMMY_NODE_ID,
-                        span: mk_sp(lo, e.span.hi),
+                        span: lo.to(e.span),
                         node: StmtKind::Expr(e),
                     }
                 }
@@ -3905,7 +3876,7 @@ impl<'a> Parser<'a> {
     pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         maybe_whole!(self, NtBlock, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
 
         if !self.eat(&token::OpenDelim(token::Brace)) {
             let sp = self.span;
@@ -3950,7 +3921,7 @@ impl<'a> Parser<'a> {
     fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
         maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
 
-        let lo = self.span.lo;
+        let lo = self.span;
         self.expect(&token::OpenDelim(token::Brace))?;
         Ok((self.parse_inner_attributes()?,
             self.parse_block_tail(lo, BlockCheckMode::Default)?))
@@ -3958,7 +3929,7 @@ impl<'a> Parser<'a> {
 
     /// Parse the rest of a block expression or function body
     /// Precondition: already parsed the '{'.
-    fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> {
+    fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
 
         while !self.eat(&token::CloseDelim(token::Brace)) {
@@ -3976,7 +3947,7 @@ impl<'a> Parser<'a> {
             stmts: stmts,
             id: ast::DUMMY_NODE_ID,
             rules: s,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
         }))
     }
 
@@ -4042,10 +4013,10 @@ impl<'a> Parser<'a> {
                 }
                 bounds.push(RegionTyParamBound(self.expect_lifetime()));
             } else if self.check_keyword(keywords::For) || self.check_path() {
-                let lo = self.span.lo;
+                let lo = self.span;
                 let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi);
+                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
                 let modifier = if question.is_some() {
                     TraitBoundModifier::Maybe
                 } else {
@@ -4166,7 +4137,7 @@ impl<'a> Parser<'a> {
     pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         maybe_whole!(self, NtGenerics, |x| x);
 
-        let span_lo = self.span.lo;
+        let span_lo = self.span;
         if self.eat_lt() {
             let (lifetime_defs, ty_params) = self.parse_generic_params()?;
             self.expect_gt()?;
@@ -4177,7 +4148,7 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
                 },
-                span: mk_sp(span_lo, self.prev_span.hi),
+                span: span_lo.to(self.prev_span),
             })
         } else {
             Ok(ast::Generics::default())
@@ -4202,7 +4173,7 @@ impl<'a> Parser<'a> {
                 }
             } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
                 // Parse associated type binding.
-                let lo = self.span.lo;
+                let lo = self.span;
                 let ident = self.parse_ident()?;
                 self.bump();
                 let ty = self.parse_ty()?;
@@ -4210,7 +4181,7 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                     ident: ident,
                     ty: ty,
-                    span: mk_sp(lo, self.prev_span.hi),
+                    span: lo.to(self.prev_span),
                 });
                 seen_binding = true;
             } else if self.check_type() {
@@ -4267,7 +4238,7 @@ impl<'a> Parser<'a> {
         }
 
         loop {
-            let lo = self.span.lo;
+            let lo = self.span;
             if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) {
                 let lifetime = self.expect_lifetime();
                 // Bounds starting with a colon are mandatory, but possibly empty.
@@ -4275,7 +4246,7 @@ impl<'a> Parser<'a> {
                 let bounds = self.parse_lt_param_bounds();
                 where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
                     ast::WhereRegionPredicate {
-                        span: mk_sp(lo, self.prev_span.hi),
+                        span: lo.to(self.prev_span),
                         lifetime: lifetime,
                         bounds: bounds,
                     }
@@ -4296,7 +4267,7 @@ impl<'a> Parser<'a> {
                     let bounds = self.parse_ty_param_bounds()?;
                     where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
                         ast::WhereBoundPredicate {
-                            span: mk_sp(lo, self.prev_span.hi),
+                            span: lo.to(self.prev_span),
                             bound_lifetimes: lifetime_defs,
                             bounded_ty: ty,
                             bounds: bounds,
@@ -4307,7 +4278,7 @@ impl<'a> Parser<'a> {
                     let rhs_ty = self.parse_ty()?;
                     where_clause.predicates.push(ast::WherePredicate::EqPredicate(
                         ast::WhereEqPredicate {
-                            span: mk_sp(lo, self.prev_span.hi),
+                            span: lo.to(self.prev_span),
                             lhs_ty: ty,
                             rhs_ty: rhs_ty,
                             id: ast::DUMMY_NODE_ID,
@@ -4404,7 +4375,7 @@ impl<'a> Parser<'a> {
         // Parse optional self parameter of a method.
         // Only a limited set of initial token sequences is considered self parameters, anything
         // else is parsed as a normal function parameter list, so some lookahead is required.
-        let eself_lo = self.span.lo;
+        let eself_lo = self.span;
         let (eself, eself_ident) = match self.token {
             token::BinOp(token::And) => {
                 // &self
@@ -4486,7 +4457,7 @@ impl<'a> Parser<'a> {
             _ => return Ok(None),
         };
 
-        let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself);
+        let eself = codemap::respan(eself_lo.to(self.prev_span), eself);
         Ok(Some(Arg::from_self(eself, eself_ident)))
     }
 
@@ -4558,8 +4529,7 @@ impl<'a> Parser<'a> {
         Ok((id, generics))
     }
 
-    fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident,
-               node: ItemKind, vis: Visibility,
+    fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility,
                attrs: Vec<Attribute>) -> P<Item> {
         P(Item {
             ident: ident,
@@ -4567,7 +4537,7 @@ impl<'a> Parser<'a> {
             id: ast::DUMMY_NODE_ID,
             node: node,
             vis: vis,
-            span: mk_sp(lo, hi)
+            span: span,
         })
     }
 
@@ -4625,7 +4595,7 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtImplItem, |x| x);
 
         let mut attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
         let vis = self.parse_visibility(false)?;
         let defaultness = self.parse_defaultness()?;
         let (name, node) = if self.eat_keyword(keywords::Type) {
@@ -4651,7 +4621,7 @@ impl<'a> Parser<'a> {
 
         Ok(ImplItem {
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
             ident: name,
             vis: vis,
             defaultness: defaultness,
@@ -4694,7 +4664,7 @@ impl<'a> Parser<'a> {
             let prev_span = self.prev_span;
             self.complain_if_pub_macro(&vis, prev_span);
 
-            let lo = self.span.lo;
+            let lo = self.span;
             let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
@@ -4704,7 +4674,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?
             }
 
-            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
+            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
@@ -4938,11 +4908,11 @@ impl<'a> Parser<'a> {
             SeqSep::trailing_allowed(token::Comma),
             |p| {
                 let attrs = p.parse_outer_attributes()?;
-                let lo = p.span.lo;
+                let lo = p.span;
                 let vis = p.parse_visibility(true)?;
                 let ty = p.parse_ty()?;
                 Ok(StructField {
-                    span: mk_sp(lo, p.span.hi),
+                    span: lo.to(p.span),
                     vis: vis,
                     ident: None,
                     id: ast::DUMMY_NODE_ID,
@@ -4956,7 +4926,7 @@ impl<'a> Parser<'a> {
 
     /// Parse a structure field declaration
     pub fn parse_single_struct_field(&mut self,
-                                     lo: BytePos,
+                                     lo: Span,
                                      vis: Visibility,
                                      attrs: Vec<Attribute> )
                                      -> PResult<'a, StructField> {
@@ -4978,7 +4948,7 @@ impl<'a> Parser<'a> {
     /// Parse an element of a struct definition
     fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
         let vis = self.parse_visibility(false)?;
         self.parse_single_struct_field(lo, vis, attrs)
     }
@@ -5056,7 +5026,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Given a termination token, parse all of the items in a module
-    fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> {
+    fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
         let mut items = vec![];
         while let Some(item) = self.parse_item()? {
             items.push(item);
@@ -5070,11 +5040,11 @@ impl<'a> Parser<'a> {
         let hi = if self.span == syntax_pos::DUMMY_SP {
             inner_lo
         } else {
-            self.prev_span.hi
+            self.prev_span
         };
 
         Ok(ast::Mod {
-            inner: mk_sp(inner_lo, hi),
+            inner: inner_lo.to(hi),
             items: items
         })
     }
@@ -5137,7 +5107,7 @@ impl<'a> Parser<'a> {
             let old_directory = self.directory.clone();
             self.push_directory(id, &outer_attrs);
             self.expect(&token::OpenDelim(token::Brace))?;
-            let mod_inner_lo = self.span.lo;
+            let mod_inner_lo = self.span;
             let attrs = self.parse_inner_attributes()?;
             let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
             self.directory = old_directory;
@@ -5280,7 +5250,7 @@ impl<'a> Parser<'a> {
         let mut p0 =
             new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
         p0.cfg_mods = self.cfg_mods;
-        let mod_inner_lo = p0.span.lo;
+        let mod_inner_lo = p0.span;
         let mod_attrs = p0.parse_inner_attributes()?;
         let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
         self.sess.included_mod_stack.borrow_mut().pop();
@@ -5288,42 +5258,42 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a function declaration from a foreign module
-    fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos,
-                             attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> {
+    fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
+                             -> PResult<'a, ForeignItem> {
         self.expect_keyword(keywords::Fn)?;
 
         let (ident, mut generics) = self.parse_fn_header()?;
         let decl = self.parse_fn_decl(true)?;
         generics.where_clause = self.parse_where_clause()?;
-        let hi = self.span.hi;
+        let hi = self.span;
         self.expect(&token::Semi)?;
         Ok(ast::ForeignItem {
             ident: ident,
             attrs: attrs,
             node: ForeignItemKind::Fn(decl, generics),
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, hi),
+            span: lo.to(hi),
             vis: vis
         })
     }
 
     /// Parse a static item from a foreign module
-    fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos,
-                                 attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> {
+    fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
+                                 -> PResult<'a, ForeignItem> {
         self.expect_keyword(keywords::Static)?;
         let mutbl = self.eat_keyword(keywords::Mut);
 
         let ident = self.parse_ident()?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
-        let hi = self.span.hi;
+        let hi = self.span;
         self.expect(&token::Semi)?;
         Ok(ForeignItem {
             ident: ident,
             attrs: attrs,
             node: ForeignItemKind::Static(ty, mutbl),
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, hi),
+            span: lo.to(hi),
             vis: vis
         })
     }
@@ -5335,7 +5305,7 @@ impl<'a> Parser<'a> {
     /// extern crate foo;
     /// extern crate bar as foo;
     fn parse_item_extern_crate(&mut self,
-                               lo: BytePos,
+                               lo: Span,
                                visibility: Visibility,
                                attrs: Vec<Attribute>)
                                 -> PResult<'a, P<Item>> {
@@ -5349,8 +5319,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Semi)?;
 
         let prev_span = self.prev_span;
-        Ok(self.mk_item(lo,
-                        prev_span.hi,
+        Ok(self.mk_item(lo.to(prev_span),
                         ident,
                         ItemKind::ExternCrate(maybe_path),
                         visibility,
@@ -5368,7 +5337,7 @@ impl<'a> Parser<'a> {
     /// extern "C" {}
     /// extern {}
     fn parse_item_foreign_mod(&mut self,
-                              lo: BytePos,
+                              lo: Span,
                               opt_abi: Option<abi::Abi>,
                               visibility: Visibility,
                               mut attrs: Vec<Attribute>)
@@ -5390,12 +5359,8 @@ impl<'a> Parser<'a> {
             abi: abi,
             items: foreign_items
         };
-        Ok(self.mk_item(lo,
-                     prev_span.hi,
-                     keywords::Invalid.ident(),
-                     ItemKind::ForeignMod(m),
-                     visibility,
-                     attrs))
+        let invalid = keywords::Invalid.ident();
+        Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs))
     }
 
     /// Parse type Foo = Bar;
@@ -5416,7 +5381,7 @@ impl<'a> Parser<'a> {
         let mut any_disr = None;
         while self.token != token::CloseDelim(token::Brace) {
             let variant_attrs = self.parse_outer_attributes()?;
-            let vlo = self.span.lo;
+            let vlo = self.span;
 
             let struct_def;
             let mut disr_expr = None;
@@ -5444,7 +5409,7 @@ impl<'a> Parser<'a> {
                 data: struct_def,
                 disr_expr: disr_expr,
             };
-            variants.push(spanned(vlo, self.prev_span.hi, vr));
+            variants.push(respan(vlo.to(self.prev_span), vr));
 
             if !self.eat(&token::Comma) { break; }
         }
@@ -5514,7 +5479,7 @@ impl<'a> Parser<'a> {
             Some(P(item))
         });
 
-        let lo = self.span.lo;
+        let lo = self.span;
 
         let visibility = self.parse_visibility(false)?;
 
@@ -5524,12 +5489,8 @@ impl<'a> Parser<'a> {
             self.expect(&token::Semi)?;
 
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
-                                    keywords::Invalid.ident(),
-                                    item_,
-                                    visibility,
-                                    attrs);
+            let invalid = keywords::Invalid.ident();
+            let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs);
             return Ok(Some(item));
         }
 
@@ -5549,8 +5510,7 @@ impl<'a> Parser<'a> {
                                        respan(fn_span, Constness::NotConst),
                                        abi)?;
                 let prev_span = self.prev_span;
-                let item = self.mk_item(lo,
-                                        prev_span.hi,
+                let item = self.mk_item(lo.to(prev_span),
                                         ident,
                                         item_,
                                         visibility,
@@ -5572,8 +5532,7 @@ impl<'a> Parser<'a> {
             };
             let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5597,8 +5556,7 @@ impl<'a> Parser<'a> {
                                        respan(const_span, Constness::Const),
                                        Abi::Rust)?;
                 let prev_span = self.prev_span;
-                let item = self.mk_item(lo,
-                                        prev_span.hi,
+                let item = self.mk_item(lo.to(prev_span),
                                         ident,
                                         item_,
                                         visibility,
@@ -5615,8 +5573,7 @@ impl<'a> Parser<'a> {
             }
             let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5632,8 +5589,7 @@ impl<'a> Parser<'a> {
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Unsafe)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5648,8 +5604,7 @@ impl<'a> Parser<'a> {
             self.expect_keyword(keywords::Impl)?;
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5665,8 +5620,7 @@ impl<'a> Parser<'a> {
                                    respan(fn_span, Constness::NotConst),
                                    Abi::Rust)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5689,8 +5643,7 @@ impl<'a> Parser<'a> {
                                    respan(fn_span, Constness::NotConst),
                                    abi)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5702,8 +5655,7 @@ impl<'a> Parser<'a> {
             let (ident, item_, extra_attrs) =
                 self.parse_item_mod(&attrs[..])?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5714,8 +5666,7 @@ impl<'a> Parser<'a> {
             // TYPE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_type()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5726,8 +5677,7 @@ impl<'a> Parser<'a> {
             // ENUM ITEM
             let (ident, item_, extra_attrs) = self.parse_item_enum()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5739,8 +5689,7 @@ impl<'a> Parser<'a> {
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Normal)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5751,8 +5700,7 @@ impl<'a> Parser<'a> {
             // IMPL ITEM
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5763,8 +5711,7 @@ impl<'a> Parser<'a> {
             // STRUCT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_struct()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5776,8 +5723,7 @@ impl<'a> Parser<'a> {
             self.bump();
             let (ident, item_, extra_attrs) = self.parse_item_union()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5794,7 +5740,7 @@ impl<'a> Parser<'a> {
     /// Parse a foreign item.
     fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
         let visibility = self.parse_visibility(false)?;
 
         if self.check_keyword(keywords::Static) {
@@ -5821,7 +5767,7 @@ impl<'a> Parser<'a> {
         attrs: Vec<Attribute> ,
         macros_allowed: bool,
         attributes_allowed: bool,
-        lo: BytePos,
+        lo: Span,
         visibility: Visibility
     ) -> PResult<'a, Option<P<Item>>> {
         if macros_allowed && self.token.is_path_start() {
@@ -5830,7 +5776,7 @@ impl<'a> Parser<'a> {
             let prev_span = self.prev_span;
             self.complain_if_pub_macro(&visibility, prev_span);
 
-            let mac_lo = self.span.lo;
+            let mac_lo = self.span;
 
             // item macro.
             let pth = self.parse_path(PathStyle::Mod)?;
@@ -5856,9 +5802,9 @@ impl<'a> Parser<'a> {
                 }
             }
 
-            let hi = self.prev_span.hi;
-            let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts });
-            let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs);
+            let hi = self.prev_span;
+            let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts });
+            let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs);
             return Ok(Some(item));
         }
 
@@ -5886,7 +5832,7 @@ impl<'a> Parser<'a> {
         self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
                                  &token::CloseDelim(token::Brace),
                                  SeqSep::trailing_allowed(token::Comma), |this| {
-            let lo = this.span.lo;
+            let lo = this.span;
             let ident = if this.eat_keyword(keywords::SelfValue) {
                 keywords::SelfValue.ident()
             } else {
@@ -5898,8 +5844,7 @@ impl<'a> Parser<'a> {
                 rename: rename,
                 id: ast::DUMMY_NODE_ID
             };
-            let hi = this.prev_span.hi;
-            Ok(spanned(lo, hi, node))
+            Ok(respan(lo.to(this.prev_span), node))
         })
     }
 
@@ -5917,21 +5862,21 @@ impl<'a> Parser<'a> {
     /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE
     /// MOD_SEP? LBRACE item_seq RBRACE
     fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> {
-        let lo = self.span.lo;
+        let lo = self.span;
         if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) ||
            self.is_import_coupler() {
             // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
             self.eat(&token::ModSep);
             let prefix = ast::Path {
                 segments: vec![PathSegment::crate_root()],
-                span: mk_sp(lo, self.span.hi),
+                span: lo.to(self.span),
             };
             let view_path_kind = if self.eat(&token::BinOp(token::Star)) {
                 ViewPathGlob(prefix)
             } else {
                 ViewPathList(prefix, self.parse_path_list_items()?)
             };
-            Ok(P(spanned(lo, self.span.hi, view_path_kind)))
+            Ok(P(respan(lo.to(self.span), view_path_kind)))
         } else {
             let prefix = self.parse_path(PathStyle::Mod)?.default_to_global();
             if self.is_import_coupler() {
@@ -5939,16 +5884,16 @@ impl<'a> Parser<'a> {
                 self.bump();
                 if self.check(&token::BinOp(token::Star)) {
                     self.bump();
-                    Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix))))
+                    Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix))))
                 } else {
                     let items = self.parse_path_list_items()?;
-                    Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items))))
+                    Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items))))
                 }
             } else {
                 // `foo::bar` or `foo::bar as baz`
                 let rename = self.parse_rename()?.
                                   unwrap_or(prefix.segments.last().unwrap().identifier);
-                Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix))))
+                Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix))))
             }
         }
     }
@@ -5964,11 +5909,11 @@ impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main
     /// entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
-        let lo = self.span.lo;
+        let lo = self.span;
         Ok(ast::Crate {
             attrs: self.parse_inner_attributes()?,
             module: self.parse_mod_items(&token::Eof, lo)?,
-            span: mk_sp(lo, self.span.lo),
+            span: lo.to(self.span),
         })
     }
 
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 9b45e364ecf34..7f40e8ee7216b 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -174,6 +174,11 @@ impl Span {
         }
         result
     }
+
+    pub fn to(self, end: Span) -> Span {
+        // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
+        Span { hi: end.hi, ..self }
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -208,7 +213,7 @@ impl serialize::UseSpecializedDecodable for Span {
         d.read_struct("Span", 2, |d| {
             let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
             let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
-            Ok(mk_sp(lo, hi))
+            Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION })
         })
     }
 }
@@ -696,11 +701,6 @@ pub struct FileLines {
 thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
                 Cell::new(default_span_debug));
 
-/* assuming that we're not in macro expansion */
-pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
-    Span {lo: lo, hi: hi, ctxt: NO_EXPANSION}
-}
-
 pub struct MacroBacktrace {
     /// span where macro was applied to generate this code
     pub call_site: Span,
diff --git a/src/test/compile-fail/imports/macro-paths.rs b/src/test/compile-fail/imports/macro-paths.rs
index 48e7ca0eee454..7c19917acc476 100644
--- a/src/test/compile-fail/imports/macro-paths.rs
+++ b/src/test/compile-fail/imports/macro-paths.rs
@@ -25,7 +25,6 @@ fn f() {
     bar::m! { //~ ERROR ambiguous
               //~| NOTE macro-expanded items do not shadow when used in a macro invocation path
         mod bar { pub use two_macros::m; } //~ NOTE could refer to the name defined here
-                                           //~^^^ NOTE in this expansion
     }
 }
 
@@ -37,6 +36,5 @@ fn g() {
     baz::m! { //~ ERROR ambiguous
               //~| NOTE macro-expanded items do not shadow when used in a macro invocation path
         mod baz { pub use two_macros::m; } //~ NOTE could refer to the name defined here
-                                           //~^^^ NOTE in this expansion
     }
 }
diff --git a/src/test/compile-fail/imports/macros.rs b/src/test/compile-fail/imports/macros.rs
index cfa7681dc2277..06b0964a3b145 100644
--- a/src/test/compile-fail/imports/macros.rs
+++ b/src/test/compile-fail/imports/macros.rs
@@ -28,7 +28,6 @@ mod m2 {
     m! { //~ ERROR ambiguous
          //~| NOTE macro-expanded macro imports do not shadow
         use foo::m; //~ NOTE could refer to the name imported here
-                    //~^^^ NOTE in this expansion
     }
 }
 
@@ -43,7 +42,6 @@ mod m3 {
         m! { //~ ERROR ambiguous
              //~| NOTE macro-expanded macro imports do not shadow
             use two_macros::n as m; //~ NOTE could refer to the name imported here
-                                    //~^^^ NOTE in this expansion
         }
     }
 }
diff --git a/src/test/compile-fail/issue-25385.rs b/src/test/compile-fail/issue-25385.rs
index 51d7baaf3e915..4aacb6840e9d5 100644
--- a/src/test/compile-fail/issue-25385.rs
+++ b/src/test/compile-fail/issue-25385.rs
@@ -21,5 +21,4 @@ fn main() {
 
     foo!(1i32.foo());
     //~^ ERROR no method named `foo` found for type `i32` in the current scope
-    //~^^ NOTE in this expansion of foo!
 }
diff --git a/src/test/run-pass/syntax-extension-source-utils.rs b/src/test/run-pass/syntax-extension-source-utils.rs
index 3b5f033d07b7d..25c7417f7eb21 100644
--- a/src/test/run-pass/syntax-extension-source-utils.rs
+++ b/src/test/run-pass/syntax-extension-source-utils.rs
@@ -22,7 +22,7 @@ macro_rules! indirect_line { () => ( line!() ) }
 
 pub fn main() {
     assert_eq!(line!(), 24);
-    assert_eq!(column!(), 4);
+    assert_eq!(column!(), 15);
     assert_eq!(indirect_line!(), 26);
     assert!((file!().ends_with("syntax-extension-source-utils.rs")));
     assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string());
diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr
index 96635032105a8..e4044f5aaf2be 100644
--- a/src/test/ui/macros/macro_path_as_generic_bound.stderr
+++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr
@@ -2,10 +2,7 @@ error[E0433]: failed to resolve. Use of undeclared type or module `m`
   --> $DIR/macro_path_as_generic_bound.rs:17:6
    |
 17 | foo!(m::m2::A);
-   | -----^^^^^^^^--
-   | |    |
-   | |    Use of undeclared type or module `m`
-   | in this macro invocation
+   |      ^^^^^^^^ Use of undeclared type or module `m`
 
 error: cannot continue compilation due to previous error
 

From 8b92255b64989ea0e7da00a2fa94fe4358a9d7a6 Mon Sep 17 00:00:00 2001
From: Phil Ellison <phil.j.ellison@gmail.com>
Date: Sat, 25 Mar 2017 09:03:22 +0000
Subject: [PATCH 11/14] Don't stutter in operator descriptions #29365

---
 src/libcore/ops.rs | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 686cc21eba1a0..d203b68c0dfd5 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -196,7 +196,7 @@ pub trait Drop {
     fn drop(&mut self);
 }
 
-/// The `Add` trait is used to specify the functionality of `+`.
+/// The addition operator `+`.
 ///
 /// # Examples
 ///
@@ -269,7 +269,7 @@ macro_rules! add_impl {
 
 add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `Sub` trait is used to specify the functionality of `-`.
+/// The subtraction operator `-`.
 ///
 /// # Examples
 ///
@@ -342,7 +342,7 @@ macro_rules! sub_impl {
 
 sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `Mul` trait is used to specify the functionality of `*`.
+/// The multiplication operator `*`.
 ///
 /// # Examples
 ///
@@ -464,7 +464,7 @@ macro_rules! mul_impl {
 
 mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `Div` trait is used to specify the functionality of `/`.
+/// The division operator `/`.
 ///
 /// # Examples
 ///
@@ -609,7 +609,7 @@ macro_rules! div_impl_float {
 
 div_impl_float! { f32 f64 }
 
-/// The `Rem` trait is used to specify the functionality of `%`.
+/// The remainder operator `%`.
 ///
 /// # Examples
 ///
@@ -689,7 +689,7 @@ macro_rules! rem_impl_float {
 
 rem_impl_float! { f32 f64 }
 
-/// The `Neg` trait is used to specify the functionality of unary `-`.
+/// The unary negation operator `-`.
 ///
 /// # Examples
 ///
@@ -768,7 +768,7 @@ macro_rules! neg_impl_unsigned {
 // neg_impl_unsigned! { usize u8 u16 u32 u64 }
 neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `Not` trait is used to specify the functionality of unary `!`.
+/// The unary logical negation operator `!`.
 ///
 /// # Examples
 ///
@@ -826,7 +826,7 @@ macro_rules! not_impl {
 
 not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `BitAnd` trait is used to specify the functionality of `&`.
+/// The bitwise AND operator `&`.
 ///
 /// # Examples
 ///
@@ -909,7 +909,7 @@ macro_rules! bitand_impl {
 
 bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `BitOr` trait is used to specify the functionality of `|`.
+/// The bitwise OR operator `|`.
 ///
 /// # Examples
 ///
@@ -992,7 +992,7 @@ macro_rules! bitor_impl {
 
 bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `BitXor` trait is used to specify the functionality of `^`.
+/// The bitwise XOR operator `^`.
 ///
 /// # Examples
 ///
@@ -1078,7 +1078,7 @@ macro_rules! bitxor_impl {
 
 bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `Shl` trait is used to specify the functionality of `<<`.
+/// The left shift operator `<<`.
 ///
 /// # Examples
 ///
@@ -1181,7 +1181,7 @@ macro_rules! shl_impl_all {
 
 shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 }
 
-/// The `Shr` trait is used to specify the functionality of `>>`.
+/// The right shift operator `>>`.
 ///
 /// # Examples
 ///
@@ -1284,7 +1284,7 @@ macro_rules! shr_impl_all {
 
 shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 
-/// The `AddAssign` trait is used to specify the functionality of `+=`.
+/// The addition assignment operator `+=`.
 ///
 /// # Examples
 ///
@@ -1340,7 +1340,7 @@ macro_rules! add_assign_impl {
 
 add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `SubAssign` trait is used to specify the functionality of `-=`.
+/// The subtraction assignment operator `-=`.
 ///
 /// # Examples
 ///
@@ -1396,7 +1396,7 @@ macro_rules! sub_assign_impl {
 
 sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `MulAssign` trait is used to specify the functionality of `*=`.
+/// The multiplication assignment operator `*=`.
 ///
 /// # Examples
 ///
@@ -1441,7 +1441,7 @@ macro_rules! mul_assign_impl {
 
 mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `DivAssign` trait is used to specify the functionality of `/=`.
+/// The division assignment operator `/=`.
 ///
 /// # Examples
 ///
@@ -1485,7 +1485,7 @@ macro_rules! div_assign_impl {
 
 div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `RemAssign` trait is used to specify the functionality of `%=`.
+/// The remainder assignment operator `%=`.
 ///
 /// # Examples
 ///
@@ -1529,7 +1529,7 @@ macro_rules! rem_assign_impl {
 
 rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 
-/// The `BitAndAssign` trait is used to specify the functionality of `&=`.
+/// The bitwise AND assignment operator `&=`.
 ///
 /// # Examples
 ///
@@ -1615,7 +1615,7 @@ macro_rules! bitand_assign_impl {
 
 bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `BitOrAssign` trait is used to specify the functionality of `|=`.
+/// The bitwise OR assignment operator `|=`.
 ///
 /// # Examples
 ///
@@ -1659,7 +1659,7 @@ macro_rules! bitor_assign_impl {
 
 bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `BitXorAssign` trait is used to specify the functionality of `^=`.
+/// The bitwise XOR assignment operator `^=`.
 ///
 /// # Examples
 ///
@@ -1703,7 +1703,7 @@ macro_rules! bitxor_assign_impl {
 
 bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-/// The `ShlAssign` trait is used to specify the functionality of `<<=`.
+/// The left shift assignment operator `<<=`.
 ///
 /// # Examples
 ///
@@ -1768,7 +1768,7 @@ macro_rules! shl_assign_impl_all {
 
 shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 
-/// The `ShrAssign` trait is used to specify the functionality of `>>=`.
+/// The right shift assignment operator `>>=`.
 ///
 /// # Examples
 ///

From 33a6a07d586437e8d4894dc35413a21ee5cfba54 Mon Sep 17 00:00:00 2001
From: Donnie Bishop <donnie.a.bishop@gmail.com>
Date: Sat, 25 Mar 2017 11:56:52 -0400
Subject: [PATCH 12/14] FromStr implementation example

---
 src/libcore/str/mod.rs | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index dfb6936da6bda..bc5df6810a9d9 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -35,6 +35,39 @@ pub mod pattern;
 /// [`from_str`]: #tymethod.from_str
 /// [`str`]: ../../std/primitive.str.html
 /// [`parse`]: ../../std/primitive.str.html#method.parse
+///
+/// # Examples
+///
+/// Basic implementation of `FromStr` on an example `Point` type:
+///
+/// ```
+/// use std::str::FromStr;
+/// use std::num::ParseIntError;
+/// 
+/// #[derive(Debug, PartialEq)]
+/// struct Point {
+///     x: i32,
+///     y: i32
+/// }
+/// 
+/// impl FromStr for Point {
+///     type Err = ParseIntError;
+/// 
+///     fn from_str(s: &str) -> Result<Self, Self::Err> {
+///         let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
+///                                  .split(",")
+///                                  .collect();
+/// 
+///         let x_fromstr = try!(coords[0].parse::<i32>());
+///         let y_fromstr = try!(coords[1].parse::<i32>());
+/// 
+///         Ok(Point { x: x_fromstr, y: y_fromstr })
+///     }
+/// }
+/// 
+/// let p = Point::from_str("(1,2)");
+/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} )
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait FromStr: Sized {
     /// The associated error which can be returned from parsing.

From 64cd0bebab1a9023dc5a4bbc38f9e6820629fbb9 Mon Sep 17 00:00:00 2001
From: Donnie Bishop <donnie.a.bishop@gmail.com>
Date: Sat, 25 Mar 2017 12:22:23 -0400
Subject: [PATCH 13/14] Remove trailing whitespace

---
 src/libcore/str/mod.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index bc5df6810a9d9..ae08a3d0a9a7d 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -43,28 +43,28 @@ pub mod pattern;
 /// ```
 /// use std::str::FromStr;
 /// use std::num::ParseIntError;
-/// 
+///
 /// #[derive(Debug, PartialEq)]
 /// struct Point {
 ///     x: i32,
 ///     y: i32
 /// }
-/// 
+///
 /// impl FromStr for Point {
 ///     type Err = ParseIntError;
-/// 
+///
 ///     fn from_str(s: &str) -> Result<Self, Self::Err> {
 ///         let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
 ///                                  .split(",")
 ///                                  .collect();
-/// 
+///
 ///         let x_fromstr = try!(coords[0].parse::<i32>());
 ///         let y_fromstr = try!(coords[1].parse::<i32>());
-/// 
+///
 ///         Ok(Point { x: x_fromstr, y: y_fromstr })
 ///     }
 /// }
-/// 
+///
 /// let p = Point::from_str("(1,2)");
 /// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} )
 /// ```

From fb5e63fc475996ee5c65fb1b8686b8db17eb1e63 Mon Sep 17 00:00:00 2001
From: Donnie Bishop <donnie.a.bishop@gmail.com>
Date: Sat, 25 Mar 2017 14:41:37 -0400
Subject: [PATCH 14/14] Change `try!` to `?`

---
 src/libcore/str/mod.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index ae08a3d0a9a7d..f3c3994ef3150 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -58,8 +58,8 @@ pub mod pattern;
 ///                                  .split(",")
 ///                                  .collect();
 ///
-///         let x_fromstr = try!(coords[0].parse::<i32>());
-///         let y_fromstr = try!(coords[1].parse::<i32>());
+///         let x_fromstr = coords[0].parse::<i32>()?;
+///         let y_fromstr = coords[1].parse::<i32>()?;
 ///
 ///         Ok(Point { x: x_fromstr, y: y_fromstr })
 ///     }