about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--src/ci/docker/cross2/Dockerfile52
-rwxr-xr-xsrc/ci/docker/cross2/build-fuchsia-toolchain.sh (renamed from src/ci/docker/dist-fuchsia/build-toolchain.sh)0
-rwxr-xr-xsrc/ci/docker/cross2/build-solaris-toolchain.sh103
-rw-r--r--src/ci/docker/cross2/shared.sh (renamed from src/ci/docker/dist-fuchsia/shared.sh)0
-rw-r--r--src/ci/docker/dist-fuchsia/Dockerfile41
-rw-r--r--src/liballoc/arc.rs6
-rw-r--r--src/liballoc/rc.rs2
-rw-r--r--src/libcore/fmt/builders.rs10
-rw-r--r--src/libcore/fmt/mod.rs19
-rw-r--r--src/libcore/sync/atomic.rs17
-rw-r--r--src/librustc/dep_graph/dep_node.rs25
-rw-r--r--src/librustc/dep_graph/graph.rs2
-rw-r--r--src/librustc/hir/def_id.rs4
-rw-r--r--src/librustc/hir/lowering.rs1
-rw-r--r--src/librustc/hir/map/definitions.rs21
-rw-r--r--src/librustc/hir/mod.rs1
-rw-r--r--src/librustc/hir/print.rs8
-rw-r--r--src/librustc/ich/impls_hir.rs3
-rw-r--r--src/librustc/middle/stability.rs2
-rw-r--r--src/librustc/mir/mod.rs13
-rw-r--r--src/librustc/session/config.rs43
-rw-r--r--src/librustc/ty/context.rs21
-rw-r--r--src/librustc_back/target/arm_linux_androideabi.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabi.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabihf.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_musleabi.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_musleabihf.rs2
-rw-r--r--src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs8
-rw-r--r--src/librustc_back/target/le32_unknown_nacl.rs51
-rw-r--r--src/librustc_back/target/mod.rs1
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs39
-rw-r--r--src/librustc_borrowck/diagnostics.rs266
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs57
-rw-r--r--src/librustc_llvm/build.rs3
-rw-r--r--src/librustc_llvm/ffi.rs56
-rw-r--r--src/librustc_llvm/lib.rs4
-rw-r--r--src/librustc_mir/borrow_check.rs33
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs165
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs31
-rw-r--r--src/librustc_mir/diagnostics.rs266
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs2
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs2
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs46
-rw-r--r--src/librustc_trans/abi.rs24
-rw-r--r--src/librustc_trans/back/link.rs43
-rw-r--r--src/librustc_trans/back/lto.rs465
-rw-r--r--src/librustc_trans/back/write.rs88
-rw-r--r--src/librustc_trans/base.rs18
-rw-r--r--src/librustc_trans/partitioning.rs12
-rw-r--r--src/librustc_trans/time_graph.rs152
-rw-r--r--src/librustdoc/clean/cfg.rs3
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/libstd/io/impls.rs8
-rw-r--r--src/libstd/os/mod.rs1
-rw-r--r--src/libstd/os/nacl/fs.rs128
-rw-r--r--src/libstd/os/nacl/raw.rs56
-rw-r--r--src/libstd/sys/unix/env.rs21
-rw-r--r--src/libstd/sys/unix/mod.rs5
-rw-r--r--src/libstd/sys/unix/os.rs2
-rw-r--r--src/libstd/sys/unix/process/process_common.rs1
-rw-r--r--src/libstd/sys/unix/process/process_fuchsia.rs10
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs4
-rw-r--r--src/libstd/sys/unix/process/zircon.rs25
-rw-r--r--src/libstd/sys_common/backtrace.rs2
-rw-r--r--src/libstd/thread/mod.rs12
-rw-r--r--src/libsyntax/parse/parser.rs7
-rw-r--r--src/libtest/lib.rs6
-rw-r--r--src/rustllvm/PassWrapper.cpp461
-rw-r--r--src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs6
-rw-r--r--src/test/codegen-units/item-collection/generic-drop-glue.rs12
-rw-r--r--src/test/codegen-units/item-collection/instantiation-through-vtable.rs4
-rw-r--r--src/test/codegen-units/item-collection/non-generic-drop-glue.rs4
-rw-r--r--src/test/codegen-units/item-collection/transitive-drop-glue.rs18
-rw-r--r--src/test/codegen-units/item-collection/tuple-drop-glue.rs8
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs8
-rw-r--r--src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs15
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs15
-rw-r--r--src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs11
-rw-r--r--src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs11
-rw-r--r--src/test/compile-fail/issue-30355.rs21
-rw-r--r--src/test/compile-fail/issue-33241.rs23
-rw-r--r--src/test/compile-fail/issue-37887.rs14
-rw-r--r--src/test/compile-fail/issue-44578.rs34
-rw-r--r--src/test/mir-opt/validate_1.rs4
-rw-r--r--src/test/mir-opt/validate_4.rs12
-rw-r--r--src/test/mir-opt/validate_5.rs4
-rw-r--r--src/test/run-make/extra-filename-with-temp-outputs/Makefile2
-rw-r--r--src/test/run-make/sepcomp-cci-copies/Makefile2
-rw-r--r--src/test/run-make/sepcomp-inlining/Makefile8
-rw-r--r--src/test/run-make/sepcomp-separate/Makefile2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs1
-rw-r--r--src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs (renamed from src/libstd/os/nacl/mod.rs)11
-rw-r--r--src/test/run-pass/thin-lto-inlines.rs39
-rw-r--r--src/test/run-pass/thin-lto-inlines2.rs38
-rw-r--r--src/test/rustdoc/fn-pointer-arg-name.rs15
-rw-r--r--src/test/ui/issue-36400.rs16
-rw-r--r--src/test/ui/issue-36400.stderr10
-rw-r--r--src/tools/build-manifest/src/main.rs2
-rw-r--r--src/tools/compiletest/src/header.rs13
-rw-r--r--src/tools/compiletest/src/main.rs27
-rw-r--r--src/tools/compiletest/src/runtest.rs36
105 files changed, 2408 insertions, 1053 deletions
diff --git a/.travis.yml b/.travis.yml
index 9e3225a103a..139f06ec570 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -115,6 +115,8 @@ matrix:
       if: branch = auto
     - env: IMAGE=cross DEPLOY=1
       if: branch = auto
+    - env: IMAGE=cross2 DEPLOY=1
+      if: branch = auto
     - env: IMAGE=dist-aarch64-linux DEPLOY=1
       if: branch = auto
     - env: IMAGE=dist-android DEPLOY=1
@@ -125,8 +127,6 @@ matrix:
       if: branch = auto
     - env: IMAGE=dist-armv7-linux DEPLOY=1
       if: branch = auto
-    - env: IMAGE=dist-fuchsia DEPLOY=1
-      if: branch = auto
     - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1
       if: branch = auto
     - env: IMAGE=dist-i686-freebsd DEPLOY=1
diff --git a/src/ci/docker/cross2/Dockerfile b/src/ci/docker/cross2/Dockerfile
new file mode 100644
index 00000000000..f5fc06767ce
--- /dev/null
+++ b/src/ci/docker/cross2/Dockerfile
@@ -0,0 +1,52 @@
+FROM ubuntu:16.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \
+  build-essential \
+  libedit-dev \
+  libgmp-dev \
+  libisl-dev \
+  libmpc-dev \
+  libmpfr-dev \
+  ninja-build \
+  nodejs \
+  python2.7-dev \
+  software-properties-common \
+  unzip
+
+RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
+RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2-testing main'
+
+WORKDIR /tmp
+COPY cross2/shared.sh cross2/build-fuchsia-toolchain.sh /tmp/
+COPY cross2/build-solaris-toolchain.sh /tmp/
+RUN /tmp/build-fuchsia-toolchain.sh
+RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
+RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV \
+    AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
+    CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
+    CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
+    AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
+    CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
+    CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \
+    AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-ar \
+    CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-gcc \
+    CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-g++ \
+    AR_x86_64_sun_solaris=x86_64-sun-solaris2.11-ar \
+    CC_x86_64_sun_solaris=x86_64-sun-solaris2.11-gcc \
+    CXX_x86_64_sun_solaris=x86_64-sun-solaris2.11-g++
+
+ENV TARGETS=x86_64-unknown-fuchsia
+ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
+ENV TARGETS=$TARGETS,sparcv9-sun-solaris
+ENV TARGETS=$TARGETS,x86_64-sun-solaris
+
+ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/cross2/build-fuchsia-toolchain.sh
index 756013a235c..756013a235c 100755
--- a/src/ci/docker/dist-fuchsia/build-toolchain.sh
+++ b/src/ci/docker/cross2/build-fuchsia-toolchain.sh
diff --git a/src/ci/docker/cross2/build-solaris-toolchain.sh b/src/ci/docker/cross2/build-solaris-toolchain.sh
new file mode 100755
index 00000000000..ae84cc62b60
--- /dev/null
+++ b/src/ci/docker/cross2/build-solaris-toolchain.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+ARCH=$1
+LIB_ARCH=$2
+APT_ARCH=$3
+BINUTILS=2.28.1
+GCC=6.4.0
+
+# First up, build binutils
+mkdir binutils
+cd binutils
+
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf -
+mkdir binutils-build
+cd binutils-build
+hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.11
+hide_output make -j10
+hide_output make install
+
+cd ../..
+rm -rf binutils
+
+# Next, download and install the relevant solaris packages
+mkdir solaris
+cd solaris
+
+dpkg --add-architecture $APT_ARCH
+apt-get update
+apt-get download           \
+  libc:$APT_ARCH           \
+  libc-dev:$APT_ARCH       \
+  libm:$APT_ARCH           \
+  libm-dev:$APT_ARCH       \
+  libpthread:$APT_ARCH     \
+  libpthread-dev:$APT_ARCH \
+  libresolv:$APT_ARCH      \
+  libresolv-dev:$APT_ARCH  \
+  librt:$APT_ARCH          \
+  librt-dev:$APT_ARCH      \
+  libsocket:$APT_ARCH      \
+  libsocket-dev:$APT_ARCH  \
+  system-crt:$APT_ARCH     \
+  system-header:$APT_ARCH
+
+for deb in *$APT_ARCH.deb; do
+  dpkg -x $deb .
+done
+
+mkdir                  /usr/local/$ARCH-sun-solaris2.11/usr
+mv usr/include         /usr/local/$ARCH-sun-solaris2.11/usr/include
+mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib
+mv     lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib
+
+ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/sys-include
+ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/include
+
+cd ..
+rm -rf solaris
+
+# Finally, download and build gcc to target solaris
+mkdir gcc
+cd gcc
+
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | tar xJf -
+cd gcc-$GCC
+
+mkdir ../gcc-build
+cd ../gcc-build
+hide_output ../gcc-$GCC/configure \
+  --enable-languages=c,c++        \
+  --target=$ARCH-sun-solaris2.11  \
+  --with-gnu-as                   \
+  --with-gnu-ld                   \
+  --disable-multilib              \
+  --disable-nls                   \
+  --disable-libgomp               \
+  --disable-libquadmath           \
+  --disable-libssp                \
+  --disable-libvtv                \
+  --disable-libcilkrts            \
+  --disable-libada                \
+  --disable-libsanitizer          \
+  --disable-libquadmath-support   \
+  --disable-lto                   \
+  --with-sysroot=/usr/local/$ARCH-sun-solaris2.11
+
+hide_output make -j10
+hide_output make install
+
+cd ../..
+rm -rf gcc
diff --git a/src/ci/docker/dist-fuchsia/shared.sh b/src/ci/docker/cross2/shared.sh
index e26c6eb6645..e26c6eb6645 100644
--- a/src/ci/docker/dist-fuchsia/shared.sh
+++ b/src/ci/docker/cross2/shared.sh
diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile
deleted file mode 100644
index bcd95924b42..00000000000
--- a/src/ci/docker/dist-fuchsia/Dockerfile
+++ /dev/null
@@ -1,41 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y \
-  build-essential \
-  bzip2 \
-  ca-certificates \
-  cmake \
-  curl \
-  file \
-  g++ \
-  gdb \
-  git \
-  libedit-dev \
-  make \
-  ninja-build \
-  nodejs \
-  python2.7-dev \
-  sudo \
-  xz-utils \
-  unzip
-
-WORKDIR /tmp
-COPY dist-fuchsia/shared.sh dist-fuchsia/build-toolchain.sh /tmp/
-RUN /tmp/build-toolchain.sh
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV \
-    AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
-    CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
-    CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
-    AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
-    CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
-    CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++
-
-ENV TARGETS=x86_64-unknown-fuchsia
-ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
-
-ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended
-ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
\ No newline at end of file
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 3b7dbd813cf..9481cd4e1a4 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -52,8 +52,10 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 /// also destroyed.
 ///
 /// Shared references in Rust disallow mutation by default, and `Arc` is no
-/// exception. If you need to mutate through an `Arc`, use [`Mutex`][mutex],
-/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types.
+/// exception: you cannot generally obtain a mutable reference to something
+/// inside an `Arc`. If you need to mutate through an `Arc`, use
+/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic]
+/// types.
 ///
 /// ## Thread Safety
 ///
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 553980d463f..2f8620cc750 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -19,7 +19,7 @@
 //! given value is destroyed, the pointed-to value is also destroyed.
 //!
 //! Shared references in Rust disallow mutation by default, and [`Rc`]
-//! is no exception: you cannot obtain a mutable reference to
+//! is no exception: you cannot generally obtain a mutable reference to
 //! something inside an [`Rc`]. If you need mutability, put a [`Cell`]
 //! or [`RefCell`] inside the [`Rc`]; see [an example of mutability
 //! inside an Rc][mutability].
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs
index b594c886b64..60b9eeb1283 100644
--- a/src/libcore/fmt/builders.rs
+++ b/src/libcore/fmt/builders.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use fmt::{self, FlagV1};
+use fmt;
 
 struct PadAdapter<'a, 'b: 'a> {
     fmt: &'a mut fmt::Formatter<'b>,
@@ -140,7 +140,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
 
@@ -233,7 +233,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
 
@@ -277,7 +277,7 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
 
@@ -519,6 +519,6 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 6c251b9eb09..1e45af5b105 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -322,7 +322,6 @@ impl<'a> ArgumentV1<'a> {
 
 // flags available in the v1 format of format_args
 #[derive(Copy, Clone)]
-#[allow(dead_code)] // SignMinus isn't currently used
 enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, }
 
 impl<'a> Arguments<'a> {
@@ -427,7 +426,7 @@ impl<'a> Display for Arguments<'a> {
     }
 }
 
-/// Format trait for the `?` character.
+/// `?` formatting.
 ///
 /// `Debug` should format the output in a programmer-facing, debugging context.
 ///
@@ -593,7 +592,7 @@ pub trait Display {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `o` character.
+/// `o` formatting.
 ///
 /// The `Octal` trait should format its output as a number in base-8.
 ///
@@ -640,7 +639,7 @@ pub trait Octal {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `b` character.
+/// `b` formatting.
 ///
 /// The `Binary` trait should format its output as a number in binary.
 ///
@@ -687,7 +686,7 @@ pub trait Binary {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `x` character.
+/// `x` formatting.
 ///
 /// The `LowerHex` trait should format its output as a number in hexadecimal, with `a` through `f`
 /// in lower case.
@@ -735,7 +734,7 @@ pub trait LowerHex {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `X` character.
+/// `X` formatting.
 ///
 /// The `UpperHex` trait should format its output as a number in hexadecimal, with `A` through `F`
 /// in upper case.
@@ -783,7 +782,7 @@ pub trait UpperHex {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `p` character.
+/// `p` formatting.
 ///
 /// The `Pointer` trait should format its output as a memory location. This is commonly presented
 /// as hexadecimal.
@@ -828,7 +827,7 @@ pub trait Pointer {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `e` character.
+/// `e` formatting.
 ///
 /// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`.
 ///
@@ -871,7 +870,7 @@ pub trait LowerExp {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `E` character.
+/// `E` formatting.
 ///
 /// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`.
 ///
@@ -1276,7 +1275,7 @@ impl<'a> Formatter<'a> {
         write(self.buf, fmt)
     }
 
-    /// Flags for formatting (packed version of rt::Flag)
+    /// Flags for formatting
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn flags(&self) -> u32 { self.flags }
 
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 465d31b5f49..524f4508c9b 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -119,7 +119,9 @@ pub fn hint_core_should_pause()
 
 /// A boolean type which can be safely shared between threads.
 ///
-/// This type has the same in-memory representation as a `bool`.
+/// This type has the same in-memory representation as a [`bool`].
+///
+/// [`bool`]: ../../../std/primitive.bool.html
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicBool {
@@ -246,11 +248,13 @@ impl AtomicBool {
         AtomicBool { v: UnsafeCell::new(v as u8) }
     }
 
-    /// Returns a mutable reference to the underlying `bool`.
+    /// Returns a mutable reference to the underlying [`bool`].
     ///
     /// This is safe because the mutable reference guarantees that no other threads are
     /// concurrently accessing the atomic data.
     ///
+    /// [`bool`]: ../../../std/primitive.bool.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -369,7 +373,7 @@ impl AtomicBool {
         unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
     }
 
-    /// Stores a value into the `bool` if the current value is the same as the `current` value.
+    /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
     ///
     /// The return value is always the previous value. If it is equal to `current`, then the value
     /// was updated.
@@ -378,6 +382,7 @@ impl AtomicBool {
     /// ordering of this operation.
     ///
     /// [`Ordering`]: enum.Ordering.html
+    /// [`bool`]: ../../../std/primitive.bool.html
     ///
     /// # Examples
     ///
@@ -401,7 +406,7 @@ impl AtomicBool {
         }
     }
 
-    /// Stores a value into the `bool` if the current value is the same as the `current` value.
+    /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
     ///
     /// The return value is a result indicating whether the new value was written and containing
     /// the previous value. On success this value is guaranteed to be equal to `current`.
@@ -412,6 +417,7 @@ impl AtomicBool {
     /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and must
     /// be equivalent or weaker than the success ordering.
     ///
+    /// [`bool`]: ../../../std/primitive.bool.html
     /// [`Ordering`]: enum.Ordering.html
     /// [`Release`]: enum.Ordering.html#variant.Release
     /// [`AcqRel`]: enum.Ordering.html#variant.Release
@@ -452,7 +458,7 @@ impl AtomicBool {
         }
     }
 
-    /// Stores a value into the `bool` if the current value is the same as the `current` value.
+    /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
     ///
     /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the
     /// comparison succeeds, which can result in more efficient code on some platforms. The
@@ -465,6 +471,7 @@ impl AtomicBool {
     /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or
     /// weaker than the success ordering.
     ///
+    /// [`bool`]: ../../../std/primitive.bool.html
     /// [`compare_exchange`]: #method.compare_exchange
     /// [`Ordering`]: enum.Ordering.html
     /// [`Release`]: enum.Ordering.html#variant.Release
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 36236ff25b0..1ecbc62225e 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -339,6 +339,25 @@ macro_rules! define_dep_nodes {
                     Ok(DepNode::new_no_params(kind))
                 }
             }
+
+            /// Used in testing
+            pub fn has_label_string(label: &str) -> bool {
+                match label {
+                    $(
+                        stringify!($variant) => true,
+                    )*
+                    _ => false,
+                }
+            }
+        }
+
+        /// Contains variant => str representations for constructing
+        /// DepNode groups for tests.
+        #[allow(dead_code, non_upper_case_globals)]
+        pub mod label_strs {
+           $(
+                pub const $variant: &'static str = stringify!($variant);
+            )*
         }
     );
 }
@@ -356,7 +375,7 @@ impl fmt::Debug for DepNode {
         ::ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
                 if let Some(def_id) = self.extract_def_id(tcx) {
-                    write!(f, "{}", tcx.def_path(def_id).to_string(tcx))?;
+                    write!(f, "{}", tcx.def_path_debug_str(def_id))?;
                 } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
                     write!(f, "{}", s)?;
                 } else {
@@ -700,8 +719,8 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId, De
         let (def_id_0, def_id_1) = *self;
 
         format!("({}, {})",
-                tcx.def_path(def_id_0).to_string(tcx),
-                tcx.def_path(def_id_1).to_string(tcx))
+                tcx.def_path_debug_str(def_id_0),
+                tcx.def_path_debug_str(def_id_1))
     }
 }
 
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index cb4126245af..8aff042955c 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -577,7 +577,7 @@ impl DepGraph {
                       "DepGraph::try_mark_green() - Duplicate DepNodeColor \
                       insertion for {:?}", dep_node);
 
-        debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node.kind);
+        debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node);
         Some(dep_node_index)
     }
 
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 8e48352007b..69d23504cda 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -197,12 +197,12 @@ pub struct DefId {
 
 impl fmt::Debug for DefId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "DefId {{ krate: {:?}, node: {:?}",
+        write!(f, "DefId {{ krate: {:?}, index: {:?}",
                self.krate, self.index)?;
 
         ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
-                write!(f, " => {}", tcx.def_path(*self).to_string(tcx))?;
+                write!(f, " => {}", tcx.def_path_debug_str(*self))?;
             }
             Ok(())
         })?;
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 1fdfbe20328..64a2ba1fa6f 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -673,6 +673,7 @@ impl<'a> LoweringContext<'a> {
                     unsafety: self.lower_unsafety(f.unsafety),
                     abi: f.abi,
                     decl: self.lower_fn_decl(&f.decl),
+                    arg_names: self.lower_fn_args_to_names(&f.decl),
                 }))
             }
             TyKind::Never => hir::TyNever,
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index bd80b613e77..8bc7cf2faba 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -27,7 +27,6 @@ use std::hash::Hash;
 use syntax::ast;
 use syntax::ext::hygiene::Mark;
 use syntax::symbol::{Symbol, InternedString};
-use ty::TyCtxt;
 use util::nodemap::NodeMap;
 
 /// The DefPathTable maps DefIndexes to DefKeys and vice versa.
@@ -296,26 +295,6 @@ impl DefPath {
         DefPath { data: data, krate: krate }
     }
 
-    pub fn to_string(&self, tcx: TyCtxt) -> String {
-        let mut s = String::with_capacity(self.data.len() * 16);
-
-        s.push_str(&tcx.original_crate_name(self.krate).as_str());
-        s.push_str("/");
-        // Don't print the whole crate disambiguator. That's just annoying in
-        // debug output.
-        s.push_str(&tcx.crate_disambiguator(self.krate).as_str()[..7]);
-
-        for component in &self.data {
-            write!(s,
-                   "::{}[{}]",
-                   component.data.as_interned_str(),
-                   component.disambiguator)
-                .unwrap();
-        }
-
-        s
-    }
-
     /// Returns a string representation of the DefPath without
     /// the crate-prefix. This method is useful if you don't have
     /// a TyCtxt available.
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index dcff66dc23b..5ad0ff04c1b 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1418,6 +1418,7 @@ pub struct BareFnTy {
     pub abi: Abi,
     pub lifetimes: HirVec<LifetimeDef>,
     pub decl: P<FnDecl>,
+    pub arg_names: HirVec<Spanned<Name>>,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 5daffe667fd..7287e599b29 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -399,7 +399,8 @@ impl<'a> State<'a> {
                     },
                     span: syntax_pos::DUMMY_SP,
                 };
-                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?;
+                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics,
+                                 &f.arg_names[..])?;
             }
             hir::TyPath(ref qpath) => {
                 self.print_qpath(qpath, false)?
@@ -2140,7 +2141,8 @@ impl<'a> State<'a> {
                        unsafety: hir::Unsafety,
                        decl: &hir::FnDecl,
                        name: Option<ast::Name>,
-                       generics: &hir::Generics)
+                       generics: &hir::Generics,
+                       arg_names: &[Spanned<ast::Name>])
                        -> io::Result<()> {
         self.ibox(indent_unit)?;
         if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
@@ -2163,7 +2165,7 @@ impl<'a> State<'a> {
                       name,
                       &generics,
                       &hir::Inherited,
-                      &[],
+                      arg_names,
                       None)?;
         self.end()
     }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 776f85cf5da..c0fae8bf8bd 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -274,7 +274,8 @@ impl_stable_hash_for!(struct hir::BareFnTy {
     unsafety,
     abi,
     lifetimes,
-    decl
+    decl,
+    arg_names
 });
 
 impl_stable_hash_for!(enum hir::Ty_ {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 89049958309..4e4fc8b3118 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -429,7 +429,7 @@ impl<'a, 'tcx> Index<'tcx> {
             // while maintaining the invariant that all sysroot crates are unstable
             // by default and are unable to be used.
             if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
-                let reason = "this crate is being loaded from the sysroot, and \
+                let reason = "this crate is being loaded from the sysroot, an \
                               unstable location; did you mean to load this crate \
                               from crates.io via `Cargo.toml` instead?";
                 let stability = tcx.intern_stability(Stability {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index b909269e153..075a629de04 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -260,6 +260,19 @@ impl<'tcx> Mir<'tcx> {
         debug_assert!(location.statement_index < block.statements.len());
         block.statements[location.statement_index].make_nop()
     }
+
+    /// Returns the source info associated with `location`.
+    pub fn source_info(&self, location: Location) -> &SourceInfo {
+        let block = &self[location.block];
+        let stmts = &block.statements;
+        let idx = location.statement_index;
+        if location.statement_index < stmts.len() {
+            &stmts[idx].source_info
+        } else {
+            assert!(location.statement_index == stmts.len());
+            &block.terminator().source_info
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 7c1d457a6ee..8b35b064eb3 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -409,9 +409,7 @@ impl_stable_hash_for!(struct self::OutputFilenames {
     outputs
 });
 
-/// Codegen unit names generated by the numbered naming scheme will contain this
-/// marker right before the index of the codegen unit.
-pub const NUMBERED_CODEGEN_UNIT_MARKER: &'static str = ".cgu-";
+pub const RUST_CGU_EXT: &str = "rust-cgu";
 
 impl OutputFilenames {
     pub fn path(&self, flavor: OutputType) -> PathBuf {
@@ -442,22 +440,14 @@ impl OutputFilenames {
         let mut extension = String::new();
 
         if let Some(codegen_unit_name) = codegen_unit_name {
-            if codegen_unit_name.contains(NUMBERED_CODEGEN_UNIT_MARKER) {
-                // If we use the numbered naming scheme for modules, we don't want
-                // the files to look like <crate-name><extra>.<crate-name>.<index>.<ext>
-                // but simply <crate-name><extra>.<index>.<ext>
-                let marker_offset = codegen_unit_name.rfind(NUMBERED_CODEGEN_UNIT_MARKER)
-                                                     .unwrap();
-                let index_offset = marker_offset + NUMBERED_CODEGEN_UNIT_MARKER.len();
-                extension.push_str(&codegen_unit_name[index_offset .. ]);
-            } else {
-                extension.push_str(codegen_unit_name);
-            };
+            extension.push_str(codegen_unit_name);
         }
 
         if !ext.is_empty() {
             if !extension.is_empty() {
                 extension.push_str(".");
+                extension.push_str(RUST_CGU_EXT);
+                extension.push_str(".");
             }
 
             extension.push_str(ext);
@@ -874,7 +864,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
          build_codegen_options, "C", "codegen",
          CG_OPTIONS, cg_type_desc, cgsetters,
     ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "tool to assemble archives with"),
+        "tool to assemble archives with (has no effect currently, \
+         rustc doesn't use an external archiver)"),
     linker: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "system linker to link outputs with"),
     link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
@@ -1060,6 +1051,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "print the result of the translation item collection pass"),
     mir_opt_level: usize = (1, parse_uint, [TRACKED],
           "set the MIR optimization level (0-3, default: 1)"),
+    mutable_noalias: bool = (false, parse_bool, [UNTRACKED],
+          "emit noalias metadata for mutable references"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
           "dump MIR state at various points in translation"),
     dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
@@ -1105,6 +1098,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
                  "run the non-lexical lifetimes MIR pass"),
     trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
         "generate a graphical HTML report of time spent in trans and LLVM"),
+    thinlto: bool = (false, parse_bool, [TRACKED],
+        "enable ThinLTO when possible"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -1716,7 +1711,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
 
     let codegen_units = codegen_units.unwrap_or_else(|| {
         match opt_level {
-            // If we're compiling at `-O0` then default to 32 codegen units.
+            // If we're compiling at `-O0` then default to 16 codegen units.
             // The number here shouldn't matter too too much as debug mode
             // builds don't rely on performance at all, meaning that lost
             // opportunities for inlining through multiple codegen units is
@@ -1734,7 +1729,21 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
             // unit takes *too* long to build we'll be guaranteed that all
             // cpus will finish pretty closely to one another and we should
             // make relatively optimal use of system resources
-            OptLevel::No => 32,
+            //
+            // Another note worth mentioning here, however, is that this number
+            // isn't *too* high. When codegen units are increased that means we
+            // currently have to codegen `#[inline]` functions into each codegen
+            // unit, which means the more codegen units we're using the more we
+            // may be generating. In other words, increasing codegen units may
+            // increase the overall work the compiler does. If we don't have
+            // enough cores to make up for this loss then increasing the number
+            // of codegen units could become an overall loss!
+            //
+            // As a result we choose a hopefully conservative value 16, which
+            // should be more than the number of cpus of most hardware compiling
+            // Rust but also not too much for 2-4 core machines to have too much
+            // loss of compile time.
+            OptLevel::No => 16,
 
             // All other optimization levels default use one codegen unit,
             // the historical default in Rust for a Long Time.
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 15e10f8c5e8..740299b91f1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1252,6 +1252,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn def_path_debug_str(self, def_id: DefId) -> String {
+        // We are explicitly not going through queries here in order to get
+        // crate name and disambiguator since this code is called from debug!()
+        // statements within the query system and we'd run into endless
+        // recursion otherwise.
+        let (crate_name, crate_disambiguator) = if def_id.is_local() {
+            (self.crate_name.clone(),
+             self.sess.local_crate_disambiguator())
+        } else {
+            (self.cstore.crate_name_untracked(def_id.krate),
+             self.cstore.crate_disambiguator_untracked(def_id.krate))
+        };
+
+        format!("{}[{}]{}",
+                crate_name,
+                // Don't print the whole crate disambiguator. That's just
+                // annoying in debug output.
+                &(crate_disambiguator.as_str())[..4],
+                self.def_path(def_id).to_string_no_crate())
+    }
+
     pub fn metadata_encoding_version(self) -> Vec<u8> {
         self.cstore.metadata_encoding_version().to_vec()
     }
diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs
index e93a9a788a4..ba21b1df032 100644
--- a/src/librustc_back/target/arm_linux_androideabi.rs
+++ b/src/librustc_back/target/arm_linux_androideabi.rs
@@ -14,7 +14,7 @@ use target::{Target, TargetOptions, TargetResult};
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
     // https://developer.android.com/ndk/guides/abis.html#armeabi
-    base.features = "+v5te".to_string();
+    base.features = "+strict-align,+v5te".to_string();
     base.max_atomic_width = Some(64);
 
     Ok(Target {
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
index b9f40accaeb..e630376a67d 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
@@ -27,7 +27,7 @@ pub fn target() -> TargetResult {
         linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
-            features: "+v6".to_string(),
+            features: "+strict-align,+v6".to_string(),
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         },
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
index a3ea69caec6..178a948b2b9 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
@@ -27,7 +27,7 @@ pub fn target() -> TargetResult {
         linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
-            features: "+v6,+vfp2".to_string(),
+            features: "+strict-align,+v6,+vfp2".to_string(),
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs
index 598f722d9af..29720ec5efc 100644
--- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabi
     // target.
-    base.features = "+v6".to_string();
+    base.features = "+strict-align,+v6".to_string();
     base.max_atomic_width = Some(64);
     Ok(Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
index ea0bf75b103..fc8313877f6 100644
--- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabihf
     // target.
-    base.features = "+v6,+vfp2".to_string();
+    base.features = "+strict-align,+v6,+vfp2".to_string();
     base.max_atomic_width = Some(64);
     Ok(Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
index b9573721678..97397ca4962 100644
--- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
@@ -27,8 +27,12 @@ pub fn target() -> TargetResult {
 
         options: TargetOptions {
             features: "+soft-float,+strict-align".to_string(),
-            // No atomic instructions on ARMv5
-            max_atomic_width: Some(0),
+
+            // Atomic operations provided when linked with libgcc.
+            // FIXME: If the following PR is merged, the atomic operations would be
+            // provided by compiler-builtins instead with no change of behavior:
+            // https://github.com/rust-lang-nursery/compiler-builtins/pull/115/files
+            max_atomic_width: Some(32),
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs
deleted file mode 100644
index 9af4606f1f1..00000000000
--- a/src/librustc_back/target/le32_unknown_nacl.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use LinkerFlavor;
-use super::{LinkArgs, Target, TargetOptions, TargetResult};
-
-pub fn target() -> TargetResult {
-    let mut pre_link_args = LinkArgs::new();
-    pre_link_args.insert(LinkerFlavor::Gcc,
-                         vec!["--pnacl-exceptions=sjlj".to_string(),
-                              "--target=le32-unknown-nacl".to_string(),
-                              "-Wl,--start-group".to_string()]);
-    let mut post_link_args = LinkArgs::new();
-    post_link_args.insert(LinkerFlavor::Gcc,
-                          vec!["-Wl,--end-group".to_string()]);
-
-    let opts = TargetOptions {
-        linker: "pnacl-clang".to_string(),
-        ar: "pnacl-ar".to_string(),
-
-        pre_link_args,
-        post_link_args,
-        dynamic_linking: false,
-        executables: true,
-        exe_suffix: ".pexe".to_string(),
-        linker_is_gnu: true,
-        allow_asm: false,
-        max_atomic_width: Some(32),
-        .. Default::default()
-    };
-    Ok(Target {
-        llvm_target: "le32-unknown-nacl".to_string(),
-        target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
-        target_c_int_width: "32".to_string(),
-        target_os: "nacl".to_string(),
-        target_env: "newlib".to_string(),
-        target_vendor: "unknown".to_string(),
-        data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(),
-        arch: "le32".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: opts,
-    })
-}
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index b1b208d2de4..039e0153656 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -215,7 +215,6 @@ supported_targets! {
     ("i686-pc-windows-msvc", i686_pc_windows_msvc),
     ("i586-pc-windows-msvc", i586_pc_windows_msvc),
 
-    ("le32-unknown-nacl", le32_unknown_nacl),
     ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-experimental-emscripten", wasm32_experimental_emscripten),
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index de3f6f08325..1f2b917bdb9 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -14,6 +14,7 @@ use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::NoteClosureEnv;
 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
 use rustc::ty;
+use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
 use syntax::ast;
 use syntax_pos;
 use errors::DiagnosticBuilder;
@@ -134,7 +135,7 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec<MoveError<'tcx>>)
 }
 
 // (keep in sync with gather_moves::check_and_get_illegal_move_origin )
-fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
+fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
                                        move_from: mc::cmt<'tcx>)
                                        -> DiagnosticBuilder<'a> {
     match move_from.cat {
@@ -142,43 +143,21 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Deref(_, mc::Implicit(..)) |
         Categorization::Deref(_, mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
-            let mut err = struct_span_err!(bccx, move_from.span, E0507,
-                             "cannot move out of {}",
-                             move_from.descriptive_string(bccx.tcx));
-            err.span_label(
-                move_from.span,
-                format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
-                );
-            err
+            bccx.cannot_move_out_of(
+                move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast)
         }
-
         Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
-            let type_name = match (&b.ty.sty, ik) {
-                (&ty::TyArray(_, _), Kind::Index) => "array",
-                (&ty::TySlice(_), _) => "slice",
-                _ => {
-                    span_bug!(move_from.span, "this path should not cause illegal move");
-                },
-            };
-            let mut err = struct_span_err!(bccx, move_from.span, E0508,
-                                           "cannot move out of type `{}`, \
-                                            a non-copy {}",
-                                           b.ty, type_name);
-            err.span_label(move_from.span, "cannot move out of here");
-            err
+            bccx.cannot_move_out_of_interior_noncopy(
+                move_from.span, b.ty, ik == Kind::Index, Origin::Ast)
         }
 
         Categorization::Downcast(ref b, _) |
         Categorization::Interior(ref b, mc::InteriorField(_)) => {
             match b.ty.sty {
                 ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
-                    let mut err = struct_span_err!(bccx, move_from.span, E0509,
-                                                   "cannot move out of type `{}`, \
-                                                   which implements the `Drop` trait",
-                                                   b.ty);
-                    err.span_label(move_from.span, "cannot move out of here");
-                    err
-                },
+                    bccx.cannot_move_out_of_interior_of_drop(
+                        move_from.span, b.ty, Origin::Ast)
+                }
                 _ => {
                     span_bug!(move_from.span, "this path should not cause illegal move");
                 }
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index 29c35e23d4e..031dbcb1ebb 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -317,272 +317,6 @@ fn main() {
 ```
 "##,
 
-E0507: r##"
-You tried to move out of a value which was borrowed. Erroneous code example:
-
-```compile_fail,E0507
-use std::cell::RefCell;
-
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-
-    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
-}
-```
-
-Here, the `nothing_is_true` method takes the ownership of `self`. However,
-`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
-which is a borrow of the content owned by the `RefCell`. To fix this error,
-you have three choices:
-
-* Try to avoid moving the variable.
-* Somehow reclaim the ownership.
-* Implement the `Copy` trait on the type.
-
-Examples:
-
-```
-use std::cell::RefCell;
-
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(&self) {} // First case, we don't take ownership
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-
-    x.borrow().nothing_is_true(); // ok!
-}
-```
-
-Or:
-
-```
-use std::cell::RefCell;
-
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-    let x = x.into_inner(); // we get back ownership
-
-    x.nothing_is_true(); // ok!
-}
-```
-
-Or:
-
-```
-use std::cell::RefCell;
-
-#[derive(Clone, Copy)] // we implement the Copy trait
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-
-    x.borrow().nothing_is_true(); // ok!
-}
-```
-
-Moving a member out of a mutably borrowed struct will also cause E0507 error:
-
-```compile_fail,E0507
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-struct Batcave {
-    knight: TheDarkKnight
-}
-
-fn main() {
-    let mut cave = Batcave {
-        knight: TheDarkKnight
-    };
-    let borrowed = &mut cave;
-
-    borrowed.knight.nothing_is_true(); // E0507
-}
-```
-
-It is fine only if you put something back. `mem::replace` can be used for that:
-
-```
-# struct TheDarkKnight;
-# impl TheDarkKnight { fn nothing_is_true(self) {} }
-# struct Batcave { knight: TheDarkKnight }
-use std::mem;
-
-let mut cave = Batcave {
-    knight: TheDarkKnight
-};
-let borrowed = &mut cave;
-
-mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
-```
-
-You can find more information about borrowing in the rust-book:
-http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
-"##,
-
-E0508: r##"
-A value was moved out of a non-copy fixed-size array.
-
-Example of erroneous code:
-
-```compile_fail,E0508
-struct NonCopy;
-
-fn main() {
-    let array = [NonCopy; 1];
-    let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
-                           //        a non-copy fixed-size array
-}
-```
-
-The first element was moved out of the array, but this is not
-possible because `NonCopy` does not implement the `Copy` trait.
-
-Consider borrowing the element instead of moving it:
-
-```
-struct NonCopy;
-
-fn main() {
-    let array = [NonCopy; 1];
-    let _value = &array[0]; // Borrowing is allowed, unlike moving.
-}
-```
-
-Alternatively, if your type implements `Clone` and you need to own the value,
-consider borrowing and then cloning:
-
-```
-#[derive(Clone)]
-struct NonCopy;
-
-fn main() {
-    let array = [NonCopy; 1];
-    // Now you can clone the array element.
-    let _value = array[0].clone();
-}
-```
-"##,
-
-E0509: r##"
-This error occurs when an attempt is made to move out of a value whose type
-implements the `Drop` trait.
-
-Example of erroneous code:
-
-```compile_fail,E0509
-struct FancyNum {
-    num: usize
-}
-
-struct DropStruct {
-    fancy: FancyNum
-}
-
-impl Drop for DropStruct {
-    fn drop(&mut self) {
-        // Destruct DropStruct, possibly using FancyNum
-    }
-}
-
-fn main() {
-    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
-    let fancy_field = drop_struct.fancy; // Error E0509
-    println!("Fancy: {}", fancy_field.num);
-    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
-}
-```
-
-Here, we tried to move a field out of a struct of type `DropStruct` which
-implements the `Drop` trait. However, a struct cannot be dropped if one or
-more of its fields have been moved.
-
-Structs implementing the `Drop` trait have an implicit destructor that gets
-called when they go out of scope. This destructor may use the fields of the
-struct, so moving out of the struct could make it impossible to run the
-destructor. Therefore, we must think of all values whose type implements the
-`Drop` trait as single units whose fields cannot be moved.
-
-This error can be fixed by creating a reference to the fields of a struct,
-enum, or tuple using the `ref` keyword:
-
-```
-struct FancyNum {
-    num: usize
-}
-
-struct DropStruct {
-    fancy: FancyNum
-}
-
-impl Drop for DropStruct {
-    fn drop(&mut self) {
-        // Destruct DropStruct, possibly using FancyNum
-    }
-}
-
-fn main() {
-    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
-    let ref fancy_field = drop_struct.fancy; // No more errors!
-    println!("Fancy: {}", fancy_field.num);
-    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
-}
-```
-
-Note that this technique can also be used in the arms of a match expression:
-
-```
-struct FancyNum {
-    num: usize
-}
-
-enum DropEnum {
-    Fancy(FancyNum)
-}
-
-impl Drop for DropEnum {
-    fn drop(&mut self) {
-        // Destruct DropEnum, possibly using FancyNum
-    }
-}
-
-fn main() {
-    // Creates and enum of type `DropEnum`, which implements `Drop`
-    let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
-    match drop_enum {
-        // Creates a reference to the inside of `DropEnum::Fancy`
-        DropEnum::Fancy(ref fancy_field) => // No error!
-            println!("It was fancy-- {}!", fancy_field.num),
-    }
-    // implicit call to `drop_enum.drop()` as drop_enum goes out of scope
-}
-```
-"##,
-
 E0595: r##"
 Closures cannot mutate immutable captured variables.
 
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 33a9cb58c51..0270e3618e2 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -39,6 +39,8 @@
 //! previous revision to compare things to.
 //!
 
+use std::collections::HashSet;
+use std::vec::Vec;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -54,6 +56,8 @@ use rustc::ty::TyCtxt;
 const LABEL: &'static str = "label";
 const CFG: &'static str = "cfg";
 
+type Labels = HashSet<String>;
+
 pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // can't add `#[rustc_dirty]` etc without opting in to this feature
     if !tcx.sess.features.borrow().rustc_attrs {
@@ -87,23 +91,46 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
-    fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode {
-        let def_path_hash = self.tcx.def_path_hash(def_id);
+    fn labels(&self, attr: &Attribute) -> Labels {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
             if item.check_name(LABEL) {
                 let value = expect_associated_value(self.tcx, &item);
-                match DepNode::from_label_string(&value.as_str(), def_path_hash) {
-                    Ok(dep_node) => return dep_node,
-                    Err(()) => {
-                        self.tcx.sess.span_fatal(
-                            item.span,
-                            &format!("dep-node label `{}` not recognized", value));
-                    }
+                return self.resolve_labels(&item, value.as_str().as_ref());
+            }
+        }
+        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+    }
+
+    fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels {
+        let mut out: Labels = HashSet::new();
+        for label in value.split(',') {
+            let label = label.trim();
+            if DepNode::has_label_string(label) {
+                if out.contains(label) {
+                    self.tcx.sess.span_fatal(
+                        item.span,
+                        &format!("dep-node label `{}` is repeated", label));
                 }
+                out.insert(label.to_string());
+            } else {
+                self.tcx.sess.span_fatal(
+                    item.span,
+                    &format!("dep-node label `{}` not recognized", label));
             }
         }
+        out
+    }
 
-        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+    fn dep_nodes(&self, labels: &Labels, def_id: DefId) -> Vec<DepNode> {
+        let mut out = Vec::with_capacity(labels.len());
+        let def_path_hash = self.tcx.def_path_hash(def_id);
+        for label in labels.iter() {
+            match DepNode::from_label_string(label, def_path_hash) {
+                Ok(dep_node) => out.push(dep_node),
+                Err(()) => unreachable!(),
+            }
+        }
+        out
     }
 
     fn dep_node_str(&self, dep_node: &DepNode) -> String {
@@ -150,12 +177,18 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
             if attr.check_name(ATTR_DIRTY) {
                 if check_config(self.tcx, attr) {
                     self.checked_attrs.insert(attr.id);
-                    self.assert_dirty(item_span, self.dep_node(attr, def_id));
+                    let labels = self.labels(attr);
+                    for dep_node in self.dep_nodes(&labels, def_id) {
+                        self.assert_dirty(item_span, dep_node);
+                    }
                 }
             } else if attr.check_name(ATTR_CLEAN) {
                 if check_config(self.tcx, attr) {
                     self.checked_attrs.insert(attr.id);
-                    self.assert_clean(item_span, self.dep_node(attr, def_id));
+                    let labels = self.labels(attr);
+                    for dep_node in self.dep_nodes(&labels, def_id) {
+                        self.assert_clean(item_span, dep_node);
+                    }
                 }
             }
         }
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index dde7a38efc7..75efe135f65 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -88,7 +88,7 @@ fn main() {
     let is_crossed = target != host;
 
     let mut optional_components =
-        vec!["x86", "arm", "aarch64", "mips", "powerpc", "pnacl",
+        vec!["x86", "arm", "aarch64", "mips", "powerpc",
              "systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx"];
 
     let mut version_cmd = Command::new(&llvm_config);
@@ -115,6 +115,7 @@ fn main() {
                                 "linker",
                                 "asmparser",
                                 "mcjit",
+                                "lto",
                                 "interpreter",
                                 "instrumentation"];
 
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index fd4a136f50b..3399bf2acd8 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -345,6 +345,20 @@ pub enum PassKind {
     Module,
 }
 
+/// LLVMRustThinLTOData
+pub enum ThinLTOData {}
+
+/// LLVMRustThinLTOBuffer
+pub enum ThinLTOBuffer {}
+
+/// LLVMRustThinLTOModule
+#[repr(C)]
+pub struct ThinLTOModule {
+    pub identifier: *const c_char,
+    pub data: *const u8,
+    pub len: usize,
+}
+
 // Opaque pointer types
 #[allow(missing_copy_implementations)]
 pub enum Module_opaque {}
@@ -1271,6 +1285,9 @@ extern "C" {
                                                         PM: PassManagerRef,
                                                         Internalize: Bool,
                                                         RunInliner: Bool);
+    pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
+        PMB: PassManagerBuilderRef,
+        PM: PassManagerRef) -> bool;
 
     // Stuff that's in rustllvm/ because it's not upstream yet.
 
@@ -1685,4 +1702,43 @@ extern "C" {
     pub fn LLVMRustModuleBufferLen(p: *const ModuleBuffer) -> usize;
     pub fn LLVMRustModuleBufferFree(p: *mut ModuleBuffer);
     pub fn LLVMRustModuleCost(M: ModuleRef) -> u64;
+
+    pub fn LLVMRustThinLTOAvailable() -> bool;
+    pub fn LLVMRustWriteThinBitcodeToFile(PMR: PassManagerRef,
+                                          M: ModuleRef,
+                                          BC: *const c_char) -> bool;
+    pub fn LLVMRustThinLTOBufferCreate(M: ModuleRef) -> *mut ThinLTOBuffer;
+    pub fn LLVMRustThinLTOBufferFree(M: *mut ThinLTOBuffer);
+    pub fn LLVMRustThinLTOBufferPtr(M: *const ThinLTOBuffer) -> *const c_char;
+    pub fn LLVMRustThinLTOBufferLen(M: *const ThinLTOBuffer) -> size_t;
+    pub fn LLVMRustCreateThinLTOData(
+        Modules: *const ThinLTOModule,
+        NumModules: c_uint,
+        PreservedSymbols: *const *const c_char,
+        PreservedSymbolsLen: c_uint,
+    ) -> *mut ThinLTOData;
+    pub fn LLVMRustPrepareThinLTORename(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustPrepareThinLTOResolveWeak(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustPrepareThinLTOInternalize(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustPrepareThinLTOImport(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustFreeThinLTOData(Data: *mut ThinLTOData);
+    pub fn LLVMRustParseBitcodeForThinLTO(
+        Context: ContextRef,
+        Data: *const u8,
+        len: usize,
+        Identifier: *const c_char,
+    ) -> ModuleRef;
+    pub fn LLVMGetModuleIdentifier(M: ModuleRef, size: *mut usize) -> *const c_char;
 }
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 9be5f5b5486..98172bca177 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -346,10 +346,6 @@ pub fn initialize_available_targets() {
                  LLVMInitializePowerPCTargetMC,
                  LLVMInitializePowerPCAsmPrinter,
                  LLVMInitializePowerPCAsmParser);
-    init_target!(llvm_component = "pnacl",
-                 LLVMInitializePNaClTargetInfo,
-                 LLVMInitializePNaClTarget,
-                 LLVMInitializePNaClTargetMC);
     init_target!(llvm_component = "systemz",
                  LLVMInitializeSystemZTargetInfo,
                  LLVMInitializeSystemZTarget,
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index 14b6e319132..db6a0ee4ba5 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -30,6 +30,7 @@ use dataflow::{MoveDataParamEnv};
 use dataflow::{BitDenotation, BlockSets, DataflowResults, DataflowResultsConsumer};
 use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
 use dataflow::{Borrows, BorrowData, BorrowIndex};
+use dataflow::move_paths::{MoveError, IllegalMoveOriginKind};
 use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult};
 use util::borrowck_errors::{BorrowckErrors, Origin};
 
@@ -59,7 +60,33 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
     let param_env = tcx.param_env(def_id);
     tcx.infer_ctxt().enter(|_infcx| {
 
-        let move_data = MoveData::gather_moves(mir, tcx, param_env);
+        let move_data = match MoveData::gather_moves(mir, tcx, param_env) {
+            Ok(move_data) => move_data,
+            Err((move_data, move_errors)) => {
+                for move_error in move_errors {
+                    let (span, kind): (Span, IllegalMoveOriginKind) = match move_error {
+                        MoveError::UnionMove { .. } =>
+                            unimplemented!("dont know how to report union move errors yet."),
+                        MoveError::IllegalMove { cannot_move_out_of: o } => (o.span, o.kind),
+                    };
+                    let origin = Origin::Mir;
+                    let mut err = match kind {
+                        IllegalMoveOriginKind::Static =>
+                            tcx.cannot_move_out_of(span, "static item", origin),
+                        IllegalMoveOriginKind::BorrowedContent =>
+                            tcx.cannot_move_out_of(span, "borrowed_content", origin),
+                        IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } =>
+                            tcx.cannot_move_out_of_interior_of_drop(span, ty, origin),
+                        IllegalMoveOriginKind::InteriorOfSlice { elem_ty: ty, is_index } =>
+                            tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin),
+                        IllegalMoveOriginKind::InteriorOfArray { elem_ty: ty, is_index } =>
+                            tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin),
+                    };
+                    err.emit();
+                }
+                move_data
+            }
+        };
         let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
         let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
         let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
@@ -1106,9 +1133,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
 
     // Retrieve span of given borrow from the current MIR representation
     fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
-        self.mir.basic_blocks()[borrow.location.block]
-            .statements[borrow.location.statement_index]
-            .source_info.span
+        self.mir.source_info(borrow.location).span
     }
 }
 
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 86298c3b83e..0790d937ceb 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -22,17 +22,15 @@ use std::mem;
 use super::abs_domain::Lift;
 
 use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
+use super::{MoveError};
+use super::IllegalMoveOriginKind::*;
 
-pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
+struct MoveDataBuilder<'a, 'tcx: 'a> {
     mir: &'a Mir<'tcx>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     data: MoveData<'tcx>,
-}
-
-pub enum MovePathError {
-    IllegalMove,
-    UnionMove { path: MovePathIndex },
+    errors: Vec<MoveError<'tcx>>,
 }
 
 impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -47,6 +45,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             mir,
             tcx,
             param_env,
+            errors: Vec::new(),
             data: MoveData {
                 moves: IndexVec::new(),
                 loc_map: LocationMap::new(mir),
@@ -85,7 +84,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         assert_eq!(path_map_ent, move_path);
         move_path
     }
+}
 
+impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     /// This creates a MovePath for a given lvalue, returning an `MovePathError`
     /// if that lvalue can't be moved from.
     ///
@@ -94,13 +95,15 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
     ///
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
-                     -> Result<MovePathIndex, MovePathError>
+                     -> Result<MovePathIndex, MoveError<'tcx>>
     {
         debug!("lookup({:?})", lval);
         match *lval {
-            Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
-            // error: can't move out of a static
-            Lvalue::Static(..) => Err(MovePathError::IllegalMove),
+            Lvalue::Local(local) => Ok(self.builder.data.rev_lookup.locals[local]),
+            Lvalue::Static(..) => {
+                let span = self.builder.mir.source_info(self.loc).span;
+                Err(MoveError::cannot_move_out_of(span, Static))
+            }
             Lvalue::Projection(ref proj) => {
                 self.move_path_for_projection(lval, proj)
             }
@@ -116,37 +119,52 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
     fn move_path_for_projection(&mut self,
                                 lval: &Lvalue<'tcx>,
                                 proj: &LvalueProjection<'tcx>)
-                                -> Result<MovePathIndex, MovePathError>
+                                -> Result<MovePathIndex, MoveError<'tcx>>
     {
         let base = try!(self.move_path_for(&proj.base));
-        let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
+        let mir = self.builder.mir;
+        let tcx = self.builder.tcx;
+        let lv_ty = proj.base.ty(mir, tcx).to_ty(tcx);
         match lv_ty.sty {
-            // error: can't move out of borrowed content
-            ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
-            // error: can't move out of struct with destructor
-            ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
-                return Err(MovePathError::IllegalMove),
+            ty::TyRef(..) | ty::TyRawPtr(..) =>
+                return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
+                                                         BorrowedContent)),
+            ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
+                return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
+                                                         InteriorOfTypeWithDestructor {
+                    container_ty: lv_ty
+                })),
             // move out of union - always move the entire union
             ty::TyAdt(adt, _) if adt.is_union() =>
-                return Err(MovePathError::UnionMove { path: base }),
-            // error: can't move out of a slice
-            ty::TySlice(..) =>
-                return Err(MovePathError::IllegalMove),
-            ty::TyArray(..) => match proj.elem {
-                // error: can't move out of an array
-                ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove),
+                return Err(MoveError::UnionMove { path: base }),
+            ty::TySlice(elem_ty) =>
+                return Err(MoveError::cannot_move_out_of(
+                    mir.source_info(self.loc).span,
+                    InteriorOfSlice {
+                        elem_ty, is_index: match proj.elem {
+                            ProjectionElem::Index(..) => true,
+                            _ => false
+                        },
+                    })),
+            ty::TyArray(elem_ty, _num_elems) => match proj.elem {
+                ProjectionElem::Index(..) =>
+                    return Err(MoveError::cannot_move_out_of(
+                        mir.source_info(self.loc).span,
+                        InteriorOfArray {
+                            elem_ty, is_index: true
+                        })),
                 _ => {
                     // FIXME: still badly broken
                 }
             },
             _ => {}
         };
-        match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
+        match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
             Entry::Occupied(ent) => Ok(*ent.get()),
             Entry::Vacant(ent) => {
-                let path = Self::new_move_path(
-                    &mut self.data.move_paths,
-                    &mut self.data.path_map,
+                let path = MoveDataBuilder::new_move_path(
+                    &mut self.builder.data.move_paths,
+                    &mut self.builder.data.path_map,
                     Some(base),
                     lval.clone()
                 );
@@ -155,8 +173,10 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             }
         }
     }
+}
 
-    fn finalize(self) -> MoveData<'tcx> {
+impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+    fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
         debug!("{}", {
             debug!("moves for {:?}:", self.mir.span);
             for (j, mo) in self.data.moves.iter_enumerated() {
@@ -168,14 +188,20 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             }
             "done dumping moves"
         });
-        self.data
+
+        if self.errors.len() > 0 {
+            Err((self.data, self.errors))
+        } else {
+            Ok(self.data)
+        }
     }
 }
 
 pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
                                      tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      param_env: ty::ParamEnv<'tcx>)
-                                     -> MoveData<'tcx> {
+                                     -> Result<MoveData<'tcx>,
+                                               (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
     let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
 
     for (bb, block) in mir.basic_blocks().iter_enumerated() {
@@ -197,6 +223,22 @@ pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
 impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
     fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) {
         debug!("gather_statement({:?}, {:?})", loc, stmt);
+        (Gatherer { builder: self, loc }).gather_statement(stmt);
+    }
+
+    fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
+        debug!("gather_terminator({:?}, {:?})", loc, term);
+        (Gatherer { builder: self, loc }).gather_terminator(term);
+    }
+}
+
+struct Gatherer<'b, 'a: 'b, 'tcx: 'a> {
+    builder: &'b mut MoveDataBuilder<'a, 'tcx>,
+    loc: Location,
+}
+
+impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
+    fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
         match stmt.kind {
             StatementKind::Assign(ref lval, ref rval) => {
                 self.create_move_path(lval);
@@ -206,7 +248,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
                     // the exterior.
                     self.create_move_path(&lval.clone().deref());
                 }
-                self.gather_rvalue(loc, rval);
+                self.gather_rvalue(rval);
             }
             StatementKind::StorageLive(_) |
             StatementKind::StorageDead(_) => {}
@@ -221,22 +263,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         }
     }
 
-    fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) {
+    fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
         match *rvalue {
             Rvalue::Use(ref operand) |
             Rvalue::Repeat(ref operand, _) |
             Rvalue::Cast(_, ref operand, _) |
             Rvalue::UnaryOp(_, ref operand) => {
-                self.gather_operand(loc, operand)
+                self.gather_operand(operand)
             }
             Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) |
             Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
-                self.gather_operand(loc, lhs);
-                self.gather_operand(loc, rhs);
+                self.gather_operand(lhs);
+                self.gather_operand(rhs);
             }
             Rvalue::Aggregate(ref _kind, ref operands) => {
                 for operand in operands {
-                    self.gather_operand(loc, operand);
+                    self.gather_operand(operand);
                 }
             }
             Rvalue::Ref(..) |
@@ -258,8 +300,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         }
     }
 
-    fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
-        debug!("gather_terminator({:?}, {:?})", loc, term);
+    fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
         match term.kind {
             TerminatorKind::Goto { target: _ } |
             TerminatorKind::Resume |
@@ -267,7 +308,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             TerminatorKind::Unreachable => { }
 
             TerminatorKind::Return => {
-                self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
+                self.gather_move(&Lvalue::Local(RETURN_POINTER));
             }
 
             TerminatorKind::Assert { .. } |
@@ -276,20 +317,20 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             }
 
             TerminatorKind::Yield { ref value, .. } => {
-                self.gather_operand(loc, value);
+                self.gather_operand(value);
             }
 
             TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
-                self.gather_move(loc, location);
+                self.gather_move(location);
             }
             TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
                 self.create_move_path(location);
-                self.gather_operand(loc, value);
+                self.gather_operand(value);
             }
             TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
-                self.gather_operand(loc, func);
+                self.gather_operand(func);
                 for arg in args {
-                    self.gather_operand(loc, arg);
+                    self.gather_operand(arg);
                 }
                 if let Some((ref destination, _bb)) = *destination {
                     self.create_move_path(destination);
@@ -298,40 +339,38 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         }
     }
 
-    fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) {
+    fn gather_operand(&mut self, operand: &Operand<'tcx>) {
         match *operand {
             Operand::Constant(..) => {} // not-a-move
             Operand::Consume(ref lval) => { // a move
-                self.gather_move(loc, lval);
+                self.gather_move(lval);
             }
         }
     }
 
-    fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) {
-        debug!("gather_move({:?}, {:?})", loc, lval);
+    fn gather_move(&mut self, lval: &Lvalue<'tcx>) {
+        debug!("gather_move({:?}, {:?})", self.loc, lval);
 
-        let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx);
-        if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) {
-            debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty);
+        let tcx = self.builder.tcx;
+        let lv_ty = lval.ty(self.builder.mir, tcx).to_ty(tcx);
+        if !lv_ty.moves_by_default(tcx, self.builder.param_env, DUMMY_SP) {
+            debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", self.loc, lval, lv_ty);
             return
         }
 
         let path = match self.move_path_for(lval) {
-            Ok(path) | Err(MovePathError::UnionMove { path }) => path,
-            Err(MovePathError::IllegalMove) => {
-                // Moving out of a bad path. Eventually, this should be a MIR
-                // borrowck error instead of a bug.
-                span_bug!(self.mir.span,
-                          "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}",
-                          lval, lv_ty, loc);
+            Ok(path) | Err(MoveError::UnionMove { path }) => path,
+            Err(error @ MoveError::IllegalMove { .. }) => {
+                self.builder.errors.push(error);
+                return;
             }
         };
-        let move_out = self.data.moves.push(MoveOut { path: path, source: loc });
+        let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
 
         debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
-               loc, lval, move_out, path);
+               self.loc, lval, move_out, path);
 
-        self.data.path_map[path].push(move_out);
-        self.data.loc_map[loc].push(move_out);
+        self.builder.data.path_map[path].push(move_out);
+        self.builder.data.loc_map[self.loc].push(move_out);
     }
 }
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index d2d80649846..9369156a223 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -13,6 +13,7 @@ use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_vec::{IndexVec};
+use syntax_pos::{Span};
 
 use std::fmt;
 use std::ops::{Index, IndexMut};
@@ -227,11 +228,39 @@ impl<'tcx> MovePathLookup<'tcx> {
     }
 }
 
+#[derive(Debug)]
+pub struct IllegalMoveOrigin<'tcx> {
+    pub(crate) span: Span,
+    pub(crate) kind: IllegalMoveOriginKind<'tcx>,
+}
+
+#[derive(Debug)]
+pub(crate) enum IllegalMoveOriginKind<'tcx> {
+    Static,
+    BorrowedContent,
+    InteriorOfTypeWithDestructor { container_ty: ty::Ty<'tcx> },
+    InteriorOfSlice { elem_ty: ty::Ty<'tcx>, is_index: bool, },
+    InteriorOfArray { elem_ty: ty::Ty<'tcx>, is_index: bool, },
+}
+
+#[derive(Debug)]
+pub enum MoveError<'tcx> {
+    IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> },
+    UnionMove { path: MovePathIndex },
+}
+
+impl<'tcx> MoveError<'tcx> {
+    fn cannot_move_out_of(span: Span, kind: IllegalMoveOriginKind<'tcx>) -> Self {
+        let origin = IllegalMoveOrigin { span, kind };
+        MoveError::IllegalMove { cannot_move_out_of: origin }
+    }
+}
+
 impl<'a, 'tcx> MoveData<'tcx> {
     pub fn gather_moves(mir: &Mir<'tcx>,
                         tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         param_env: ty::ParamEnv<'tcx>)
-                        -> Self {
+                        -> Result<Self, (Self, Vec<MoveError<'tcx>>)> {
         builder::gather_moves(mir, tcx, param_env)
     }
 }
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 950bdff1d0f..645af0bff64 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -999,6 +999,272 @@ fn print_fancy_ref(fancy_ref: &FancyNum){
 ```
 "##,
 
+E0507: r##"
+You tried to move out of a value which was borrowed. Erroneous code example:
+
+```compile_fail,E0507
+use std::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
+}
+```
+
+Here, the `nothing_is_true` method takes the ownership of `self`. However,
+`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
+which is a borrow of the content owned by the `RefCell`. To fix this error,
+you have three choices:
+
+* Try to avoid moving the variable.
+* Somehow reclaim the ownership.
+* Implement the `Copy` trait on the type.
+
+Examples:
+
+```
+use std::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(&self) {} // First case, we don't take ownership
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); // ok!
+}
+```
+
+Or:
+
+```
+use std::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+    let x = x.into_inner(); // we get back ownership
+
+    x.nothing_is_true(); // ok!
+}
+```
+
+Or:
+
+```
+use std::cell::RefCell;
+
+#[derive(Clone, Copy)] // we implement the Copy trait
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); // ok!
+}
+```
+
+Moving a member out of a mutably borrowed struct will also cause E0507 error:
+
+```compile_fail,E0507
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+struct Batcave {
+    knight: TheDarkKnight
+}
+
+fn main() {
+    let mut cave = Batcave {
+        knight: TheDarkKnight
+    };
+    let borrowed = &mut cave;
+
+    borrowed.knight.nothing_is_true(); // E0507
+}
+```
+
+It is fine only if you put something back. `mem::replace` can be used for that:
+
+```
+# struct TheDarkKnight;
+# impl TheDarkKnight { fn nothing_is_true(self) {} }
+# struct Batcave { knight: TheDarkKnight }
+use std::mem;
+
+let mut cave = Batcave {
+    knight: TheDarkKnight
+};
+let borrowed = &mut cave;
+
+mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
+```
+
+You can find more information about borrowing in the rust-book:
+http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
+"##,
+
+E0508: r##"
+A value was moved out of a non-copy fixed-size array.
+
+Example of erroneous code:
+
+```compile_fail,E0508
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
+                           //        a non-copy fixed-size array
+}
+```
+
+The first element was moved out of the array, but this is not
+possible because `NonCopy` does not implement the `Copy` trait.
+
+Consider borrowing the element instead of moving it:
+
+```
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = &array[0]; // Borrowing is allowed, unlike moving.
+}
+```
+
+Alternatively, if your type implements `Clone` and you need to own the value,
+consider borrowing and then cloning:
+
+```
+#[derive(Clone)]
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    // Now you can clone the array element.
+    let _value = array[0].clone();
+}
+```
+"##,
+
+E0509: r##"
+This error occurs when an attempt is made to move out of a value whose type
+implements the `Drop` trait.
+
+Example of erroneous code:
+
+```compile_fail,E0509
+struct FancyNum {
+    num: usize
+}
+
+struct DropStruct {
+    fancy: FancyNum
+}
+
+impl Drop for DropStruct {
+    fn drop(&mut self) {
+        // Destruct DropStruct, possibly using FancyNum
+    }
+}
+
+fn main() {
+    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
+    let fancy_field = drop_struct.fancy; // Error E0509
+    println!("Fancy: {}", fancy_field.num);
+    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
+}
+```
+
+Here, we tried to move a field out of a struct of type `DropStruct` which
+implements the `Drop` trait. However, a struct cannot be dropped if one or
+more of its fields have been moved.
+
+Structs implementing the `Drop` trait have an implicit destructor that gets
+called when they go out of scope. This destructor may use the fields of the
+struct, so moving out of the struct could make it impossible to run the
+destructor. Therefore, we must think of all values whose type implements the
+`Drop` trait as single units whose fields cannot be moved.
+
+This error can be fixed by creating a reference to the fields of a struct,
+enum, or tuple using the `ref` keyword:
+
+```
+struct FancyNum {
+    num: usize
+}
+
+struct DropStruct {
+    fancy: FancyNum
+}
+
+impl Drop for DropStruct {
+    fn drop(&mut self) {
+        // Destruct DropStruct, possibly using FancyNum
+    }
+}
+
+fn main() {
+    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
+    let ref fancy_field = drop_struct.fancy; // No more errors!
+    println!("Fancy: {}", fancy_field.num);
+    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
+}
+```
+
+Note that this technique can also be used in the arms of a match expression:
+
+```
+struct FancyNum {
+    num: usize
+}
+
+enum DropEnum {
+    Fancy(FancyNum)
+}
+
+impl Drop for DropEnum {
+    fn drop(&mut self) {
+        // Destruct DropEnum, possibly using FancyNum
+    }
+}
+
+fn main() {
+    // Creates and enum of type `DropEnum`, which implements `Drop`
+    let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
+    match drop_enum {
+        // Creates a reference to the inside of `DropEnum::Fancy`
+        DropEnum::Fancy(ref fancy_field) => // No error!
+            println!("It was fancy-- {}!", fancy_field.num),
+    }
+    // implicit call to `drop_enum.drop()` as drop_enum goes out of scope
+}
+```
+"##,
+
 }
 
 register_diagnostics! {
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index c833904adba..be1b794ecdf 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -45,7 +45,7 @@ impl MirPass for ElaborateDrops {
         }
         let id = src.item_id();
         let param_env = tcx.param_env(tcx.hir.local_def_id(id));
-        let move_data = MoveData::gather_moves(mir, tcx, param_env);
+        let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
         let elaborate_patch = {
             let mir = &*mir;
             let env = MoveDataParamEnv {
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index ceff52409b2..8d6458d7934 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -45,7 +45,7 @@ impl MirPass for SanityCheck {
 
         let attributes = tcx.get_attrs(def_id);
         let param_env = tcx.param_env(def_id);
-        let move_data = MoveData::gather_moves(mir, tcx, param_env);
+        let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
         let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
         let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
         let flow_inits =
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 81e3cd7f61f..37d53ca829e 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -248,6 +248,52 @@ pub trait BorrowckErrors {
     {
         self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
     }
+
+    fn cannot_move_out_of(&self, move_from_span: Span, move_from_desc: &str, o: Origin)
+                          -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self, move_from_span, E0507,
+                                       "cannot move out of {}{OGN}",
+                                       move_from_desc, OGN=o);
+        err.span_label(
+            move_from_span,
+            format!("cannot move out of {}", move_from_desc));
+        err
+    }
+
+    fn cannot_move_out_of_interior_noncopy(&self,
+                                           move_from_span: Span,
+                                           ty: ty::Ty,
+                                           is_index: bool,
+                                           o: Origin)
+                                           -> DiagnosticBuilder
+    {
+        let type_name = match (&ty.sty, is_index) {
+            (&ty::TyArray(_, _), true) => "array",
+            (&ty::TySlice(_),    _) => "slice",
+            _ => span_bug!(move_from_span, "this path should not cause illegal move"),
+        };
+        let mut err = struct_span_err!(self, move_from_span, E0508,
+                                       "cannot move out of type `{}`, \
+                                        a non-copy {}{OGN}",
+                                       ty, type_name, OGN=o);
+        err.span_label(move_from_span, "cannot move out of here");
+        err
+    }
+
+    fn cannot_move_out_of_interior_of_drop(&self,
+                                           move_from_span: Span,
+                                           container_ty: ty::Ty,
+                                           o: Origin)
+                                           -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self, move_from_span, E0509,
+                                       "cannot move out of type `{}`, \
+                                        which implements the `Drop` trait{OGN}",
+                                       container_ty, OGN=o);
+        err.span_label(move_from_span, "cannot move out of here");
+        err
+    }
 }
 
 impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> {
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 2aecc016a5c..c3b6ede24b0 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -37,6 +37,7 @@ use type_of;
 use rustc::hir;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size};
+use rustc_back::PanicStrategy;
 
 use libc::c_uint;
 use std::cmp;
@@ -750,9 +751,7 @@ impl<'a, 'tcx> FnType<'tcx> {
                 Some(ty.boxed_ty())
             }
 
-            ty::TyRef(b, mt) => {
-                use rustc::ty::{BrAnon, ReLateBound};
-
+            ty::TyRef(_, mt) => {
                 // `&mut` pointer parameters never alias other parameters, or mutable global data
                 //
                 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
@@ -760,7 +759,17 @@ impl<'a, 'tcx> FnType<'tcx> {
                 // on memory dependencies rather than pointer equality
                 let is_freeze = ccx.shared().type_is_freeze(mt.ty);
 
-                if mt.mutbl != hir::MutMutable && is_freeze {
+                let no_alias_is_safe =
+                    if ccx.shared().tcx().sess.opts.debugging_opts.mutable_noalias ||
+                       ccx.shared().tcx().sess.panic_strategy() == PanicStrategy::Abort {
+                        // Mutable refrences or immutable shared references
+                        mt.mutbl == hir::MutMutable || is_freeze
+                    } else {
+                        // Only immutable shared references
+                        mt.mutbl != hir::MutMutable && is_freeze
+                    };
+
+                if no_alias_is_safe {
                     arg.attrs.set(ArgAttribute::NoAlias);
                 }
 
@@ -768,13 +777,6 @@ impl<'a, 'tcx> FnType<'tcx> {
                     arg.attrs.set(ArgAttribute::ReadOnly);
                 }
 
-                // When a reference in an argument has no named lifetime, it's
-                // impossible for that reference to escape this function
-                // (returned or stored beyond the call by a closure).
-                if let ReLateBound(_, BrAnon(_)) = *b {
-                    arg.attrs.set(ArgAttribute::NoCapture);
-                }
-
                 Some(mt.ty)
             }
             _ => None
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 3badc1b9a69..3f25c182fa2 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -16,6 +16,7 @@ use super::rpath::RPathConfig;
 use super::rpath;
 use metadata::METADATA_FILENAME;
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
+use rustc::session::config::RUST_CGU_EXT;
 use rustc::session::filesearch;
 use rustc::session::search_paths::PathKind;
 use rustc::session::Session;
@@ -45,13 +46,9 @@ use syntax::attr;
 /// The LLVM module name containing crate-metadata. This includes a `.` on
 /// purpose, so it cannot clash with the name of a user-defined module.
 pub const METADATA_MODULE_NAME: &'static str = "crate.metadata";
-/// The name of the crate-metadata object file the compiler generates. Must
-/// match up with `METADATA_MODULE_NAME`.
-pub const METADATA_OBJ_NAME: &'static str = "crate.metadata.o";
 
 // same as for metadata above, but for allocator shim
 pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator";
-pub const ALLOCATOR_OBJ_NAME: &'static str = "crate.allocator.o";
 
 pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
                                   invalid_output_for_target, build_link_meta, out_filename,
@@ -129,6 +126,14 @@ fn command_path(sess: &Session) -> OsString {
     env::join_paths(new_path).unwrap()
 }
 
+fn metadata_obj(outputs: &OutputFilenames) -> PathBuf {
+    outputs.temp_path(OutputType::Object, Some(METADATA_MODULE_NAME))
+}
+
+fn allocator_obj(outputs: &OutputFilenames) -> PathBuf {
+    outputs.temp_path(OutputType::Object, Some(ALLOCATOR_MODULE_NAME))
+}
+
 pub fn remove(sess: &Session, path: &Path) {
     match fs::remove_file(path) {
         Ok(..) => {}
@@ -174,9 +179,9 @@ pub fn link_binary(sess: &Session,
                 remove(sess, &obj.object);
             }
         }
-        remove(sess, &outputs.with_extension(METADATA_OBJ_NAME));
+        remove(sess, &metadata_obj(outputs));
         if trans.allocator_module.is_some() {
-            remove(sess, &outputs.with_extension(ALLOCATOR_OBJ_NAME));
+            remove(sess, &allocator_obj(outputs));
         }
     }
 
@@ -478,7 +483,7 @@ fn link_rlib<'a>(sess: &'a Session,
 
         RlibFlavor::StaticlibBase => {
             if trans.allocator_module.is_some() {
-                ab.add_file(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+                ab.add_file(&allocator_obj(outputs));
             }
         }
     }
@@ -908,11 +913,11 @@ fn link_args(cmd: &mut Linker,
     // object file, so we link that in here.
     if crate_type == config::CrateTypeDylib ||
        crate_type == config::CrateTypeProcMacro {
-        cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME));
+        cmd.add_object(&metadata_obj(outputs));
     }
 
     if trans.allocator_module.is_some() {
-        cmd.add_object(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+        cmd.add_object(&allocator_obj(outputs));
     }
 
     // Try to strip as much out of the generated object by removing unused
@@ -1265,11 +1270,23 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                 let canonical = f.replace("-", "_");
                 let canonical_name = name.replace("-", "_");
 
+                // Look for `.rust-cgu.o` at the end of the filename to conclude
+                // that this is a Rust-related object file.
+                fn looks_like_rust(s: &str) -> bool {
+                    let path = Path::new(s);
+                    let ext = path.extension().and_then(|s| s.to_str());
+                    if ext != Some(OutputType::Object.extension()) {
+                        return false
+                    }
+                    let ext2 = path.file_stem()
+                        .and_then(|s| Path::new(s).extension())
+                        .and_then(|s| s.to_str());
+                    ext2 == Some(RUST_CGU_EXT)
+                }
+
                 let is_rust_object =
-                    canonical.starts_with(&canonical_name) && {
-                        let num = &f[name.len()..f.len() - 2];
-                        num.len() > 0 && num[1..].parse::<u32>().is_ok()
-                    };
+                    canonical.starts_with(&canonical_name) &&
+                    looks_like_rust(&f);
 
                 // If we've been requested to skip all native object files
                 // (those not generated by the rust compiler) then we can skip
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 8651b95b12a..8f75b891a30 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -9,23 +9,25 @@
 // except according to those terms.
 
 use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
-use back::write;
 use back::symbol_export;
-use rustc::session::config;
+use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
+use back::write;
 use errors::{FatalError, Handler};
-use llvm;
 use llvm::archive_ro::ArchiveRO;
 use llvm::{ModuleRef, TargetMachineRef, True, False};
+use llvm;
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::middle::exported_symbols::SymbolExportLevel;
+use rustc::session::config;
 use rustc::util::common::time;
-use rustc::hir::def_id::LOCAL_CRATE;
-use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
-use {ModuleTranslation, ModuleKind};
+use time_graph::Timeline;
+use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource};
 
 use libc;
 
 use std::ffi::CString;
 use std::slice;
+use std::sync::Arc;
 
 pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
     match crate_type {
@@ -45,14 +47,14 @@ pub enum LtoModuleTranslation {
         _serialized_bitcode: Vec<SerializedModule>,
     },
 
-    // Note the lack of other entries in this enum! Ideally one day this gap is
-    // intended to be filled with a "Thin" LTO variant.
+    Thin(ThinModule),
 }
 
 impl LtoModuleTranslation {
     pub fn name(&self) -> &str {
         match *self {
             LtoModuleTranslation::Fat { .. } => "everything",
+            LtoModuleTranslation::Thin(ref m) => m.name(),
         }
     }
 
@@ -62,7 +64,9 @@ impl LtoModuleTranslation {
     /// points to LLVM data structures owned by this `LtoModuleTranslation`.
     /// It's intended that the module returned is immediately code generated and
     /// dropped, and then this LTO module is dropped.
-    pub unsafe fn optimize(&mut self, cgcx: &CodegenContext)
+    pub unsafe fn optimize(&mut self,
+                           cgcx: &CodegenContext,
+                           timeline: &mut Timeline)
         -> Result<ModuleTranslation, FatalError>
     {
         match *self {
@@ -71,9 +75,11 @@ impl LtoModuleTranslation {
                 let config = cgcx.config(trans.kind);
                 let llmod = trans.llvm().unwrap().llmod;
                 let tm = trans.llvm().unwrap().tm;
-                run_pass_manager(cgcx, tm, llmod, config);
+                run_pass_manager(cgcx, tm, llmod, config, false);
+                timeline.record("fat-done");
                 Ok(trans)
             }
+            LtoModuleTranslation::Thin(ref mut thin) => thin.optimize(cgcx, timeline),
         }
     }
 
@@ -83,33 +89,31 @@ impl LtoModuleTranslation {
         match *self {
             // Only one module with fat LTO, so the cost doesn't matter.
             LtoModuleTranslation::Fat { .. } => 0,
+            LtoModuleTranslation::Thin(ref m) => m.cost(),
         }
     }
 }
 
-pub fn run(cgcx: &CodegenContext, modules: Vec<ModuleTranslation>)
+pub enum LTOMode {
+    WholeCrateGraph,
+    JustThisCrate,
+}
+
+pub fn run(cgcx: &CodegenContext,
+           modules: Vec<ModuleTranslation>,
+           mode: LTOMode,
+           timeline: &mut Timeline)
     -> Result<Vec<LtoModuleTranslation>, FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
-    if cgcx.opts.cg.prefer_dynamic {
-        diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
-                    .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
-                           supported with LTO")
-                    .emit();
-        return Err(FatalError)
-    }
-
-    // Make sure we actually can run LTO
-    for crate_type in cgcx.crate_types.iter() {
-        if !crate_type_allows_lto(*crate_type) {
-            let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \
-                                        static library outputs");
-            return Err(e)
+    let export_threshold = match mode {
+        LTOMode::WholeCrateGraph => {
+            symbol_export::crates_export_threshold(&cgcx.crate_types)
         }
-    }
-
-    let export_threshold =
-        symbol_export::crates_export_threshold(&cgcx.crate_types);
+        LTOMode::JustThisCrate => {
+            SymbolExportLevel::Rust
+        }
+    };
 
     let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
         if level.is_below_threshold(export_threshold) {
@@ -121,55 +125,81 @@ pub fn run(cgcx: &CodegenContext, modules: Vec<ModuleTranslation>)
         }
     };
 
-    let mut symbol_white_list: Vec<CString> = cgcx.exported_symbols[&LOCAL_CRATE]
+    let mut symbol_white_list = cgcx.exported_symbols[&LOCAL_CRATE]
         .iter()
         .filter_map(symbol_filter)
-        .collect();
-    info!("{} symbols in whitelist", symbol_white_list.len());
+        .collect::<Vec<CString>>();
+    timeline.record("whitelist");
 
-    // For each of our upstream dependencies, find the corresponding rlib and
-    // load the bitcode from the archive. Then merge it into the current LLVM
-    // module that we've got.
+    // If we're performing LTO for the entire crate graph, then for each of our
+    // upstream dependencies, find the corresponding rlib and load the bitcode
+    // from the archive.
+    //
+    // We save off all the bytecode and LLVM module ids for later processing
+    // with either fat or thin LTO
     let mut upstream_modules = Vec::new();
-    for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
-        symbol_white_list.extend(
-            cgcx.exported_symbols[&cnum]
-                .iter()
-                .filter_map(symbol_filter));
-        info!("{} symbols in whitelist after {}", symbol_white_list.len(), cnum);
-
-        let archive = ArchiveRO::open(&path).expect("wanted an rlib");
-        let bytecodes = archive.iter().filter_map(|child| {
-            child.ok().and_then(|c| c.name().map(|name| (name, c)))
-        }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION));
-        for (name, data) in bytecodes {
-            info!("adding bytecode {}", name);
-            let bc_encoded = data.data();
-
-            let (bc, id) = time(cgcx.time_passes, &format!("decode {}", name), || {
-                match DecodedBytecode::new(bc_encoded) {
-                    Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
-                    Err(e) => Err(diag_handler.fatal(&e)),
-                }
-            })?;
-            let bc = SerializedModule::FromRlib(bc);
-            upstream_modules.push((bc, CString::new(id).unwrap()));
+    if let LTOMode::WholeCrateGraph = mode {
+        if cgcx.opts.cg.prefer_dynamic {
+            diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
+                        .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
+                               supported with LTO")
+                        .emit();
+            return Err(FatalError)
+        }
+
+        // Make sure we actually can run LTO
+        for crate_type in cgcx.crate_types.iter() {
+            if !crate_type_allows_lto(*crate_type) {
+                let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \
+                                            static library outputs");
+                return Err(e)
+            }
         }
-    }
 
-    // Internalize everything but the exported symbols of the current module
-    let arr: Vec<*const libc::c_char> = symbol_white_list.iter()
-                                                         .map(|c| c.as_ptr())
-                                                         .collect();
+        for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
+            symbol_white_list.extend(
+                cgcx.exported_symbols[&cnum]
+                    .iter()
+                    .filter_map(symbol_filter));
+
+            let archive = ArchiveRO::open(&path).expect("wanted an rlib");
+            let bytecodes = archive.iter().filter_map(|child| {
+                child.ok().and_then(|c| c.name().map(|name| (name, c)))
+            }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION));
+            for (name, data) in bytecodes {
+                info!("adding bytecode {}", name);
+                let bc_encoded = data.data();
+
+                let (bc, id) = time(cgcx.time_passes, &format!("decode {}", name), || {
+                    match DecodedBytecode::new(bc_encoded) {
+                        Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
+                        Err(e) => Err(diag_handler.fatal(&e)),
+                    }
+                })?;
+                let bc = SerializedModule::FromRlib(bc);
+                upstream_modules.push((bc, CString::new(id).unwrap()));
+            }
+            timeline.record(&format!("load: {}", path.display()));
+        }
+    }
 
-    fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr)
+    let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
+    match mode {
+        LTOMode::WholeCrateGraph if !cgcx.thinlto => {
+            fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
+        }
+        _ => {
+            thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
+        }
+    }
 }
 
 fn fat_lto(cgcx: &CodegenContext,
            diag_handler: &Handler,
            mut modules: Vec<ModuleTranslation>,
            mut serialized_modules: Vec<(SerializedModule, CString)>,
-           symbol_white_list: &[*const libc::c_char])
+           symbol_white_list: &[*const libc::c_char],
+           timeline: &mut Timeline)
     -> Result<Vec<LtoModuleTranslation>, FatalError>
 {
     info!("going for a fat lto");
@@ -228,6 +258,7 @@ fn fat_lto(cgcx: &CodegenContext,
                 Err(write::llvm_err(&diag_handler, msg))
             }
         })?;
+        timeline.record(&format!("link {:?}", name));
         serialized_bitcode.push(bc_decoded);
     }
     cgcx.save_temp_bitcode(&module, "lto.input");
@@ -248,6 +279,7 @@ fn fat_lto(cgcx: &CodegenContext,
         }
         cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
     }
+    timeline.record("passes");
 
     Ok(vec![LtoModuleTranslation::Fat {
         module: Some(module),
@@ -255,11 +287,143 @@ fn fat_lto(cgcx: &CodegenContext,
     }])
 }
 
+/// Prepare "thin" LTO to get run on these modules.
+///
+/// The general structure of ThinLTO is quite different from the structure of
+/// "fat" LTO above. With "fat" LTO all LLVM modules in question are merged into
+/// one giant LLVM module, and then we run more optimization passes over this
+/// big module after internalizing most symbols. Thin LTO, on the other hand,
+/// avoid this large bottleneck through more targeted optimization.
+///
+/// At a high level Thin LTO looks like:
+///
+///     1. Prepare a "summary" of each LLVM module in question which describes
+///        the values inside, cost of the values, etc.
+///     2. Merge the summaries of all modules in question into one "index"
+///     3. Perform some global analysis on this index
+///     4. For each module, use the index and analysis calculated previously to
+///        perform local transformations on the module, for example inlining
+///        small functions from other modules.
+///     5. Run thin-specific optimization passes over each module, and then code
+///        generate everything at the end.
+///
+/// The summary for each module is intended to be quite cheap, and the global
+/// index is relatively quite cheap to create as well. As a result, the goal of
+/// ThinLTO is to reduce the bottleneck on LTO and enable LTO to be used in more
+/// situations. For example one cheap optimization is that we can parallelize
+/// all codegen modules, easily making use of all the cores on a machine.
+///
+/// With all that in mind, the function here is designed at specifically just
+/// calculating the *index* for ThinLTO. This index will then be shared amongst
+/// all of the `LtoModuleTranslation` units returned below and destroyed once
+/// they all go out of scope.
+fn thin_lto(diag_handler: &Handler,
+            modules: Vec<ModuleTranslation>,
+            serialized_modules: Vec<(SerializedModule, CString)>,
+            symbol_white_list: &[*const libc::c_char],
+            timeline: &mut Timeline)
+    -> Result<Vec<LtoModuleTranslation>, FatalError>
+{
+    unsafe {
+        info!("going for that thin, thin LTO");
+
+        let mut thin_buffers = Vec::new();
+        let mut module_names = Vec::new();
+        let mut thin_modules = Vec::new();
+
+        // FIXME: right now, like with fat LTO, we serialize all in-memory
+        //        modules before working with them and ThinLTO. We really
+        //        shouldn't do this, however, and instead figure out how to
+        //        extract a summary from an in-memory module and then merge that
+        //        into the global index. It turns out that this loop is by far
+        //        the most expensive portion of this small bit of global
+        //        analysis!
+        for (i, module) in modules.iter().enumerate() {
+            info!("local module: {} - {}", i, module.llmod_id);
+            let llvm = module.llvm().expect("can't lto pretranslated module");
+            let name = CString::new(module.llmod_id.clone()).unwrap();
+            let buffer = llvm::LLVMRustThinLTOBufferCreate(llvm.llmod);
+            let buffer = ThinBuffer(buffer);
+            thin_modules.push(llvm::ThinLTOModule {
+                identifier: name.as_ptr(),
+                data: buffer.data().as_ptr(),
+                len: buffer.data().len(),
+            });
+            thin_buffers.push(buffer);
+            module_names.push(name);
+            timeline.record(&module.llmod_id);
+        }
+
+        // FIXME: All upstream crates are deserialized internally in the
+        //        function below to extract their summary and modules. Note that
+        //        unlike the loop above we *must* decode and/or read something
+        //        here as these are all just serialized files on disk. An
+        //        improvement, however, to make here would be to store the
+        //        module summary separately from the actual module itself. Right
+        //        now this is store in one large bitcode file, and the entire
+        //        file is deflate-compressed. We could try to bypass some of the
+        //        decompression by storing the index uncompressed and only
+        //        lazily decompressing the bytecode if necessary.
+        //
+        //        Note that truly taking advantage of this optimization will
+        //        likely be further down the road. We'd have to implement
+        //        incremental ThinLTO first where we could actually avoid
+        //        looking at upstream modules entirely sometimes (the contents,
+        //        we must always unconditionally look at the index).
+        let mut serialized = Vec::new();
+        for (module, name) in serialized_modules {
+            info!("foreign module {:?}", name);
+            thin_modules.push(llvm::ThinLTOModule {
+                identifier: name.as_ptr(),
+                data: module.data().as_ptr(),
+                len: module.data().len(),
+            });
+            serialized.push(module);
+            module_names.push(name);
+        }
+
+        // Delegate to the C++ bindings to create some data here. Once this is a
+        // tried-and-true interface we may wish to try to upstream some of this
+        // to LLVM itself, right now we reimplement a lot of what they do
+        // upstream...
+        let data = llvm::LLVMRustCreateThinLTOData(
+            thin_modules.as_ptr(),
+            thin_modules.len() as u32,
+            symbol_white_list.as_ptr(),
+            symbol_white_list.len() as u32,
+        );
+        if data.is_null() {
+            let msg = format!("failed to prepare thin LTO context");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        let data = ThinData(data);
+        info!("thin LTO data created");
+        timeline.record("data");
+
+        // Throw our data in an `Arc` as we'll be sharing it across threads. We
+        // also put all memory referenced by the C++ data (buffers, ids, etc)
+        // into the arc as well. After this we'll create a thin module
+        // translation per module in this data.
+        let shared = Arc::new(ThinShared {
+            data,
+            thin_buffers,
+            serialized_modules: serialized,
+            module_names,
+        });
+        Ok((0..shared.module_names.len()).map(|i| {
+            LtoModuleTranslation::Thin(ThinModule {
+                shared: shared.clone(),
+                idx: i,
+            })
+        }).collect())
+    }
+}
+
 fn run_pass_manager(cgcx: &CodegenContext,
                     tm: TargetMachineRef,
                     llmod: ModuleRef,
-                    config: &ModuleConfig) {
-
+                    config: &ModuleConfig,
+                    thin: bool) {
     // Now we have one massive module inside of llmod. Time to run the
     // LTO-specific optimization passes that LLVM provides.
     //
@@ -274,9 +438,15 @@ fn run_pass_manager(cgcx: &CodegenContext,
         llvm::LLVMRustAddPass(pm, pass);
 
         with_llvm_pmb(llmod, config, &mut |b| {
-            llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
-                /* Internalize = */ False,
-                /* RunInliner = */ True);
+            if thin {
+                if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
+                    panic!("this version of LLVM does not support ThinLTO");
+                }
+            } else {
+                llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
+                    /* Internalize = */ False,
+                    /* RunInliner = */ True);
+            }
         });
 
         let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
@@ -331,3 +501,158 @@ impl Drop for ModuleBuffer {
         unsafe { llvm::LLVMRustModuleBufferFree(self.0); }
     }
 }
+
+pub struct ThinModule {
+    shared: Arc<ThinShared>,
+    idx: usize,
+}
+
+struct ThinShared {
+    data: ThinData,
+    thin_buffers: Vec<ThinBuffer>,
+    serialized_modules: Vec<SerializedModule>,
+    module_names: Vec<CString>,
+}
+
+struct ThinData(*mut llvm::ThinLTOData);
+
+unsafe impl Send for ThinData {}
+unsafe impl Sync for ThinData {}
+
+impl Drop for ThinData {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustFreeThinLTOData(self.0);
+        }
+    }
+}
+
+struct ThinBuffer(*mut llvm::ThinLTOBuffer);
+
+unsafe impl Send for ThinBuffer {}
+unsafe impl Sync for ThinBuffer {}
+
+impl ThinBuffer {
+    fn data(&self) -> &[u8] {
+        unsafe {
+            let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
+            let len = llvm::LLVMRustThinLTOBufferLen(self.0);
+            slice::from_raw_parts(ptr, len)
+        }
+    }
+}
+
+impl Drop for ThinBuffer {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustThinLTOBufferFree(self.0);
+        }
+    }
+}
+
+impl ThinModule {
+    fn name(&self) -> &str {
+        self.shared.module_names[self.idx].to_str().unwrap()
+    }
+
+    fn cost(&self) -> u64 {
+        // Yes, that's correct, we're using the size of the bytecode as an
+        // indicator for how costly this codegen unit is.
+        self.data().len() as u64
+    }
+
+    fn data(&self) -> &[u8] {
+        let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
+        a.unwrap_or_else(|| {
+            let len = self.shared.thin_buffers.len();
+            self.shared.serialized_modules[self.idx - len].data()
+        })
+    }
+
+    unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline)
+        -> Result<ModuleTranslation, FatalError>
+    {
+        let diag_handler = cgcx.create_diag_handler();
+        let tm = (cgcx.tm_factory)().map_err(|e| {
+            write::llvm_err(&diag_handler, e)
+        })?;
+
+        // Right now the implementation we've got only works over serialized
+        // modules, so we create a fresh new LLVM context and parse the module
+        // into that context. One day, however, we may do this for upstream
+        // crates but for locally translated modules we may be able to reuse
+        // that LLVM Context and Module.
+        let llcx = llvm::LLVMContextCreate();
+        let llmod = llvm::LLVMRustParseBitcodeForThinLTO(
+            llcx,
+            self.data().as_ptr(),
+            self.data().len(),
+            self.shared.module_names[self.idx].as_ptr(),
+        );
+        assert!(!llmod.is_null());
+        let mtrans = ModuleTranslation {
+            source: ModuleSource::Translated(ModuleLlvm {
+                llmod,
+                llcx,
+                tm,
+            }),
+            llmod_id: self.name().to_string(),
+            name: self.name().to_string(),
+            kind: ModuleKind::Regular,
+        };
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-input");
+
+        // Like with "fat" LTO, get some better optimizations if landing pads
+        // are disabled by removing all landing pads.
+        if cgcx.no_landing_pads {
+            llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
+            cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-nounwind");
+            timeline.record("nounwind");
+        }
+
+        // Up next comes the per-module local analyses that we do for Thin LTO.
+        // Each of these functions is basically copied from the LLVM
+        // implementation and then tailored to suit this implementation. Ideally
+        // each of these would be supported by upstream LLVM but that's perhaps
+        // a patch for another day!
+        //
+        // You can find some more comments about these functions in the LLVM
+        // bindings we've got (currently `PassWrapper.cpp`)
+        if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rename");
+        timeline.record("rename");
+        if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-resolve");
+        timeline.record("resolve");
+        if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-internalize");
+        timeline.record("internalize");
+        if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-import");
+        timeline.record("import");
+
+        // Alright now that we've done everything related to the ThinLTO
+        // analysis it's time to run some optimizations! Here we use the same
+        // `run_pass_manager` as the "fat" LTO above except that we tell it to
+        // populate a thin-specific pass manager, which presumably LLVM treats a
+        // little differently.
+        info!("running thin lto passes over {}", mtrans.name);
+        let config = cgcx.config(mtrans.kind);
+        run_pass_manager(cgcx, tm, llmod, config, true);
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-pm");
+        timeline.record("thin-done");
+        Ok(mtrans)
+    }
+}
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 1988b9f76e4..b3b2384a027 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -19,7 +19,7 @@ use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Pas
                              AllPasses, Sanitizer};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
-use time_graph::{self, TimeGraph};
+use time_graph::{self, TimeGraph, Timeline};
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
 use llvm::{SMDiagnosticRef, ContextRef};
@@ -303,6 +303,7 @@ pub struct CodegenContext {
     // Resouces needed when running LTO
     pub time_passes: bool,
     pub lto: bool,
+    pub thinlto: bool,
     pub no_landing_pads: bool,
     pub save_temps: bool,
     pub exported_symbols: Arc<ExportedSymbols>,
@@ -315,6 +316,8 @@ pub struct CodegenContext {
     allocator_module_config: Arc<ModuleConfig>,
     pub tm_factory: Arc<Fn() -> Result<TargetMachineRef, String> + Send + Sync>,
 
+    // Number of cgus excluding the allocator/metadata modules
+    pub total_cgus: usize,
     // Handler to use for diagnostics produced during codegen.
     pub diag_emitter: SharedEmitter,
     // LLVM passes added by plugins.
@@ -450,7 +453,8 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
 unsafe fn optimize(cgcx: &CodegenContext,
                    diag_handler: &Handler,
                    mtrans: &ModuleTranslation,
-                   config: &ModuleConfig)
+                   config: &ModuleConfig,
+                   timeline: &mut Timeline)
     -> Result<(), FatalError>
 {
     let (llmod, llcx, tm) = match mtrans.source {
@@ -529,6 +533,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
         // Finally, run the actual optimization passes
         time(config.time_passes, &format!("llvm function passes [{}]", module_name.unwrap()), ||
              llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
+        timeline.record("fpm");
         time(config.time_passes, &format!("llvm module passes [{}]", module_name.unwrap()), ||
              llvm::LLVMRunPassManager(mpm, llmod));
 
@@ -543,7 +548,18 @@ fn generate_lto_work(cgcx: &CodegenContext,
                      modules: Vec<ModuleTranslation>)
     -> Vec<(WorkItem, u64)>
 {
-    let lto_modules = lto::run(cgcx, modules).unwrap_or_else(|e| panic!(e));
+    let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
+        tg.start(TRANS_WORKER_TIMELINE,
+                 TRANS_WORK_PACKAGE_KIND,
+                 "generate lto")
+    }).unwrap_or(Timeline::noop());
+    let mode = if cgcx.lto {
+        lto::LTOMode::WholeCrateGraph
+    } else {
+        lto::LTOMode::JustThisCrate
+    };
+    let lto_modules = lto::run(cgcx, modules, mode, &mut timeline)
+        .unwrap_or_else(|e| panic!(e));
 
     lto_modules.into_iter().map(|module| {
         let cost = module.cost();
@@ -554,9 +570,11 @@ fn generate_lto_work(cgcx: &CodegenContext,
 unsafe fn codegen(cgcx: &CodegenContext,
                   diag_handler: &Handler,
                   mtrans: ModuleTranslation,
-                  config: &ModuleConfig)
+                  config: &ModuleConfig,
+                  timeline: &mut Timeline)
     -> Result<CompiledModule, FatalError>
 {
+    timeline.record("codegen");
     let (llmod, llcx, tm) = match mtrans.source {
         ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm),
         ModuleSource::Preexisting(_) => {
@@ -601,7 +619,18 @@ unsafe fn codegen(cgcx: &CodegenContext,
 
     if write_bc {
         let bc_out_c = path2cstr(&bc_out);
-        llvm::LLVMWriteBitcodeToFile(llmod, bc_out_c.as_ptr());
+        if llvm::LLVMRustThinLTOAvailable() {
+            with_codegen(tm, llmod, config.no_builtins, |cpm| {
+                llvm::LLVMRustWriteThinBitcodeToFile(
+                    cpm,
+                    llmod,
+                    bc_out_c.as_ptr(),
+                )
+            });
+        } else {
+            llvm::LLVMWriteBitcodeToFile(llmod, bc_out_c.as_ptr());
+        }
+        timeline.record("bc");
     }
 
     time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
@@ -644,7 +673,8 @@ unsafe fn codegen(cgcx: &CodegenContext,
             with_codegen(tm, llmod, config.no_builtins, |cpm| {
                 llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
                 llvm::LLVMDisposePassManager(cpm);
-            })
+            });
+            timeline.record("ir");
         }
 
         if config.emit_asm {
@@ -665,6 +695,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
             if config.emit_obj {
                 llvm::LLVMDisposeModule(llmod);
             }
+            timeline.record("asm");
         }
 
         if write_obj {
@@ -672,6 +703,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
                 write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
                                   llvm::FileType::ObjectFile)
             })?;
+            timeline.record("obj");
         }
 
         Ok(())
@@ -712,7 +744,8 @@ pub fn start_async_translation(tcx: TyCtxt,
                                time_graph: Option<TimeGraph>,
                                link: LinkMeta,
                                metadata: EncodedMetadata,
-                               coordinator_receive: Receiver<Box<Any + Send>>)
+                               coordinator_receive: Receiver<Box<Any + Send>>,
+                               total_cgus: usize)
                                -> OngoingCrateTranslation {
     let sess = tcx.sess;
     let crate_output = tcx.output_filenames(LOCAL_CRATE);
@@ -836,6 +869,7 @@ pub fn start_async_translation(tcx: TyCtxt,
                                                   shared_emitter,
                                                   trans_worker_send,
                                                   coordinator_receive,
+                                                  total_cgus,
                                                   client,
                                                   time_graph.clone(),
                                                   Arc::new(modules_config),
@@ -1080,7 +1114,9 @@ enum WorkItemResult {
     NeedsLTO(ModuleTranslation),
 }
 
-fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
+fn execute_work_item(cgcx: &CodegenContext,
+                     work_item: WorkItem,
+                     timeline: &mut Timeline)
     -> Result<WorkItemResult, FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
@@ -1089,8 +1125,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
         WorkItem::Optimize(mtrans) => mtrans,
         WorkItem::LTO(mut lto) => {
             unsafe {
-                let module = lto.optimize(cgcx)?;
-                let module = codegen(cgcx, &diag_handler, module, config)?;
+                let module = lto.optimize(cgcx, timeline)?;
+                let module = codegen(cgcx, &diag_handler, module, config, timeline)?;
                 return Ok(WorkItemResult::Compiled(module))
             }
         }
@@ -1140,9 +1176,27 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
         debug!("llvm-optimizing {:?}", module_name);
 
         unsafe {
-            optimize(cgcx, &diag_handler, &mtrans, config)?;
-            if !cgcx.lto || mtrans.kind == ModuleKind::Metadata {
-                let module = codegen(cgcx, &diag_handler, mtrans, config)?;
+            optimize(cgcx, &diag_handler, &mtrans, config, timeline)?;
+
+            let lto = cgcx.lto;
+
+            let auto_thin_lto =
+                cgcx.thinlto &&
+                cgcx.total_cgus > 1 &&
+                mtrans.kind != ModuleKind::Allocator;
+
+            // If we're a metadata module we never participate in LTO.
+            //
+            // If LTO was explicitly requested on the command line, we always
+            // LTO everything else.
+            //
+            // If LTO *wasn't* explicitly requested and we're not a metdata
+            // module, then we may automatically do ThinLTO if we've got
+            // multiple codegen units. Note, however, that the allocator module
+            // doesn't participate here automatically because of linker
+            // shenanigans later on.
+            if mtrans.kind == ModuleKind::Metadata || (!lto && !auto_thin_lto) {
+                let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?;
                 Ok(WorkItemResult::Compiled(module))
             } else {
                 Ok(WorkItemResult::NeedsLTO(mtrans))
@@ -1187,6 +1241,7 @@ fn start_executing_work(tcx: TyCtxt,
                         shared_emitter: SharedEmitter,
                         trans_worker_send: Sender<Message>,
                         coordinator_receive: Receiver<Box<Any + Send>>,
+                        total_cgus: usize,
                         jobserver: Client,
                         time_graph: Option<TimeGraph>,
                         modules_config: Arc<ModuleConfig>,
@@ -1229,6 +1284,7 @@ fn start_executing_work(tcx: TyCtxt,
         crate_types: sess.crate_types.borrow().clone(),
         each_linked_rlib_for_lto,
         lto: sess.lto(),
+        thinlto: sess.opts.debugging_opts.thinlto,
         no_landing_pads: sess.no_landing_pads(),
         save_temps: sess.opts.cg.save_temps,
         opts: Arc::new(sess.opts.clone()),
@@ -1246,6 +1302,7 @@ fn start_executing_work(tcx: TyCtxt,
         metadata_module_config: metadata_config,
         allocator_module_config: allocator_config,
         tm_factory: target_machine_factory(tcx.sess),
+        total_cgus,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
@@ -1743,12 +1800,13 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
         // as a diagnostic was already sent off to the main thread - just
         // surface that there was an error in this worker.
         bomb.result = {
-            let _timing_guard = cgcx.time_graph.as_ref().map(|tg| {
+            let timeline = cgcx.time_graph.as_ref().map(|tg| {
                 tg.start(time_graph::TimelineId(cgcx.worker),
                          LLVM_WORK_PACKAGE_KIND,
                          &work.name())
             });
-            execute_work_item(&cgcx, work).ok()
+            let mut timeline = timeline.unwrap_or(Timeline::noop());
+            execute_work_item(&cgcx, work, &mut timeline).ok()
         };
     });
 }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 8c39f579b3e..17e00ac1346 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -886,6 +886,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     check_for_rustc_errors_attr(tcx);
 
+    if tcx.sess.opts.debugging_opts.thinlto {
+        if unsafe { !llvm::LLVMRustThinLTOAvailable() } {
+            tcx.sess.fatal("this compiler's LLVM does not support ThinLTO");
+        }
+    }
 
     let crate_hash = tcx.dep_graph
                         .fingerprint_of(&DepNode::new_no_params(DepKind::Krate));
@@ -925,7 +930,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             time_graph.clone(),
             link_meta,
             metadata,
-            rx);
+            rx,
+            1);
 
         ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
         ongoing_translation.translation_finished(tcx);
@@ -961,7 +967,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         time_graph.clone(),
         link_meta,
         metadata,
-        rx);
+        rx,
+        codegen_units.len());
 
     // Translate an allocator shim, if any
     let allocator_module = if let Some(kind) = tcx.sess.allocator_kind.get() {
@@ -1224,9 +1231,6 @@ fn collect_and_partition_translation_items<'a, 'tcx>(
             .collect::<Vec<_>>()
     });
 
-    assert!(tcx.sess.opts.codegen_units == codegen_units.len() ||
-            tcx.sess.opts.debugging_opts.incremental.is_some());
-
     let translation_items: DefIdSet = items.iter().filter_map(|trans_item| {
         match *trans_item {
             TransItem::Fn(ref instance) => Some(instance.def_id()),
@@ -1372,7 +1376,9 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // crashes if the module identifier is same as other symbols
         // such as a function name in the module.
         // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
-        let llmod_id = format!("{}.rs", cgu.name());
+        let llmod_id = format!("{}-{}.rs",
+                               cgu.name(),
+                               tcx.crate_disambiguator(LOCAL_CRATE));
 
         // Instantiate translation items without filling out definitions yet...
         let scx = SharedCrateContext::new(tcx);
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 7b6daa7d133..4656d212f9b 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -108,7 +108,6 @@ use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::middle::trans::{Linkage, Visibility};
-use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -391,15 +390,6 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
     for (index, cgu) in codegen_units.iter_mut().enumerate() {
         cgu.set_name(numbered_codegen_unit_name(crate_name, index));
     }
-
-    // If the initial partitioning contained less than target_cgu_count to begin
-    // with, we won't have enough codegen units here, so add a empty units until
-    // we reach the target count
-    while codegen_units.len() < target_cgu_count {
-        let index = codegen_units.len();
-        let name = numbered_codegen_unit_name(crate_name, index);
-        codegen_units.push(CodegenUnit::new(name));
-    }
 }
 
 fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
@@ -627,7 +617,7 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
-    Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str()
+    Symbol::intern(&format!("{}{}", crate_name, index)).as_str()
 }
 
 fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_trans/time_graph.rs b/src/librustc_trans/time_graph.rs
index ec57af888e5..a8502682a80 100644
--- a/src/librustc_trans/time_graph.rs
+++ b/src/librustc_trans/time_graph.rs
@@ -9,11 +9,12 @@
 // except according to those terms.
 
 use std::collections::HashMap;
+use std::fs::File;
+use std::io::prelude::*;
 use std::marker::PhantomData;
+use std::mem;
 use std::sync::{Arc, Mutex};
 use std::time::Instant;
-use std::io::prelude::*;
-use std::fs::File;
 
 const OUTPUT_WIDTH_IN_PX: u64 = 1000;
 const TIME_LINE_HEIGHT_IN_PX: u64 = 20;
@@ -25,6 +26,7 @@ struct Timing {
     end: Instant,
     work_package_kind: WorkPackageKind,
     name: String,
+    events: Vec<(String, Instant)>,
 }
 
 #[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
@@ -44,9 +46,14 @@ pub struct TimeGraph {
 #[derive(Clone, Copy)]
 pub struct WorkPackageKind(pub &'static [&'static str]);
 
-pub struct RaiiToken {
+pub struct Timeline {
+    token: Option<RaiiToken>,
+}
+
+struct RaiiToken {
     graph: TimeGraph,
     timeline: TimelineId,
+    events: Vec<(String, Instant)>,
     // The token must not be Send:
     _marker: PhantomData<*const ()>
 }
@@ -54,7 +61,7 @@ pub struct RaiiToken {
 
 impl Drop for RaiiToken {
     fn drop(&mut self) {
-        self.graph.end(self.timeline);
+        self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new()));
     }
 }
 
@@ -68,7 +75,7 @@ impl TimeGraph {
     pub fn start(&self,
                  timeline: TimelineId,
                  work_package_kind: WorkPackageKind,
-                 name: &str) -> RaiiToken {
+                 name: &str) -> Timeline {
         {
             let mut table = self.data.lock().unwrap();
 
@@ -81,14 +88,17 @@ impl TimeGraph {
             data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string()));
         }
 
-        RaiiToken {
-            graph: self.clone(),
-            timeline,
-            _marker: PhantomData,
+        Timeline {
+            token: Some(RaiiToken {
+                graph: self.clone(),
+                timeline,
+                events: Vec::new(),
+                _marker: PhantomData,
+            }),
         }
     }
 
-    fn end(&self, timeline: TimelineId) {
+    fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) {
         let end = Instant::now();
 
         let mut table = self.data.lock().unwrap();
@@ -100,6 +110,7 @@ impl TimeGraph {
                 end,
                 work_package_kind,
                 name,
+                events,
             });
         } else {
             bug!("end timing without start?")
@@ -113,13 +124,13 @@ impl TimeGraph {
             assert!(data.open_work_package.is_none());
         }
 
-        let mut timelines: Vec<PerThread> =
+        let mut threads: Vec<PerThread> =
             table.values().map(|data| data.clone()).collect();
 
-        timelines.sort_by_key(|timeline| timeline.timings[0].start);
+        threads.sort_by_key(|timeline| timeline.timings[0].start);
 
-        let earliest_instant = timelines[0].timings[0].start;
-        let latest_instant = timelines.iter()
+        let earliest_instant = threads[0].timings[0].start;
+        let latest_instant = threads.iter()
                                        .map(|timeline| timeline.timings
                                                                .last()
                                                                .unwrap()
@@ -130,16 +141,46 @@ impl TimeGraph {
 
         let mut file = File::create(format!("{}.html", output_filename)).unwrap();
 
-        writeln!(file, "<html>").unwrap();
-        writeln!(file, "<head></head>").unwrap();
-        writeln!(file, "<body>").unwrap();
+        writeln!(file, "
+            <html>
+            <head>
+                <style>
+                    #threads a {{
+                        position: absolute;
+                        overflow: hidden;
+                    }}
+                    #threads {{
+                        height: {total_height}px;
+                        width: {width}px;
+                    }}
+
+                    .timeline {{
+                        display: none;
+                        width: {width}px;
+                        position: relative;
+                    }}
+
+                    .timeline:target {{
+                        display: block;
+                    }}
+
+                    .event {{
+                        position: absolute;
+                    }}
+                </style>
+            </head>
+            <body>
+                <div id='threads'>
+        ",
+            total_height = threads.len() * TIME_LINE_HEIGHT_STRIDE_IN_PX,
+            width = OUTPUT_WIDTH_IN_PX,
+        ).unwrap();
 
         let mut color = 0;
-
-        for (line_index, timeline) in timelines.iter().enumerate() {
+        for (line_index, thread) in threads.iter().enumerate() {
             let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX;
 
-            for span in &timeline.timings {
+            for span in &thread.timings {
                 let start = distance(earliest_instant, span.start);
                 let end = distance(earliest_instant, span.end);
 
@@ -148,13 +189,13 @@ impl TimeGraph {
 
                 let colors = span.work_package_kind.0;
 
-                writeln!(file, "<div style='position:absolute; \
-                                            overflow:hidden; \
-                                            top:{}px; \
-                                            left:{}px; \
-                                            width:{}px; \
-                                            height:{}px; \
-                                            background:{};'>{}</div>",
+                writeln!(file, "<a href='#timing{}'
+                                   style='top:{}px; \
+                                          left:{}px; \
+                                          width:{}px; \
+                                          height:{}px; \
+                                          background:{};'>{}</a>",
+                    color,
                     line_top,
                     start,
                     end - start,
@@ -167,8 +208,61 @@ impl TimeGraph {
             }
         }
 
-        writeln!(file, "</body>").unwrap();
-        writeln!(file, "</html>").unwrap();
+        writeln!(file, "
+            </div>
+        ").unwrap();
+
+        let mut idx = 0;
+        for thread in threads.iter() {
+            for timing in &thread.timings {
+                let colors = timing.work_package_kind.0;
+                let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len();
+                writeln!(file, "<div class='timeline'
+                                     id='timing{}'
+                                     style='background:{};height:{}px;'>",
+                         idx,
+                         colors[idx % colors.len()],
+                         height).unwrap();
+                idx += 1;
+                let max = distance(timing.start, timing.end);
+                for (i, &(ref event, time)) in timing.events.iter().enumerate() {
+                    let i = i as u64;
+                    let time = distance(timing.start, time);
+                    let at = normalize(time, max, OUTPUT_WIDTH_IN_PX);
+                    writeln!(file, "<span class='event'
+                                          style='left:{}px;\
+                                                 top:{}px;'>{}</span>",
+                             at,
+                             TIME_LINE_HEIGHT_IN_PX * i,
+                             event).unwrap();
+                }
+                writeln!(file, "</div>").unwrap();
+            }
+        }
+
+        writeln!(file, "
+            </body>
+            </html>
+        ").unwrap();
+    }
+}
+
+impl Timeline {
+    pub fn noop() -> Timeline {
+        Timeline { token: None }
+    }
+
+    /// Record an event which happened at this moment on this timeline.
+    ///
+    /// Events are displayed in the eventual HTML output where you can click on
+    /// a particular timeline and it'll expand to all of the events that
+    /// happened on that timeline. This can then be used to drill into a
+    /// particular timeline and see what events are happening and taking the
+    /// most time.
+    pub fn record(&mut self, name: &str) {
+        if let Some(ref mut token) = self.token {
+            token.events.push((name.to_string(), Instant::now()));
+        }
     }
 }
 
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index da8c3a5cf20..e3ce403f3c1 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -337,7 +337,6 @@ impl<'a> fmt::Display for Html<'a> {
                         "l4re" => "L4Re",
                         "linux" => "Linux",
                         "macos" => "macOS",
-                        "nacl" => "NaCl",
                         "netbsd" => "NetBSD",
                         "openbsd" => "OpenBSD",
                         "redox" => "Redox",
@@ -886,4 +885,4 @@ mod test {
                 only."
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c9afa3646b2..424f48a17e9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2491,7 +2491,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
                 type_params: Vec::new(),
                 where_predicates: Vec::new()
             },
-            decl: (&*self.decl, &[][..]).clean(cx),
+            decl: (&*self.decl, &self.arg_names[..]).clean(cx),
             abi: self.abi,
         }
     }
diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs
index d6b41ceda43..fe1179a3b4a 100644
--- a/src/libstd/io/impls.rs
+++ b/src/libstd/io/impls.rs
@@ -206,6 +206,14 @@ impl<'a> Read for &'a [u8] {
         *self = b;
         Ok(())
     }
+
+    #[inline]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        buf.extend_from_slice(*self);
+        let len = self.len();
+        *self = &self[len..];
+        Ok(len)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
index b460bd90f17..122f15d1d4c 100644
--- a/src/libstd/os/mod.rs
+++ b/src/libstd/os/mod.rs
@@ -38,7 +38,6 @@ pub mod linux;
 #[cfg(all(not(dox), target_os = "haiku"))]      pub mod haiku;
 #[cfg(all(not(dox), target_os = "ios"))]        pub mod ios;
 #[cfg(all(not(dox), target_os = "macos"))]      pub mod macos;
-#[cfg(all(not(dox), target_os = "nacl"))]       pub mod nacl;
 #[cfg(all(not(dox), target_os = "netbsd"))]     pub mod netbsd;
 #[cfg(all(not(dox), target_os = "openbsd"))]    pub mod openbsd;
 #[cfg(all(not(dox), target_os = "solaris"))]    pub mod solaris;
diff --git a/src/libstd/os/nacl/fs.rs b/src/libstd/os/nacl/fs.rs
deleted file mode 100644
index 3e0fb44b01e..00000000000
--- a/src/libstd/os/nacl/fs.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use libc;
-
-use fs::Metadata;
-use sys_common::AsInner;
-
-#[allow(deprecated)]
-use os::nacl::raw;
-
-/// OS-specific extension methods for `fs::Metadata`
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned `stat` are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(since = "1.8.0",
-                       reason = "deprecated in favor of the accessor \
-                                 methods of this trait")]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe {
-            &*(self.as_inner().as_inner() as *const libc::stat64
-                                          as *const raw::stat)
-        }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-}
diff --git a/src/libstd/os/nacl/raw.rs b/src/libstd/os/nacl/raw.rs
deleted file mode 100644
index 3c3d4410a2a..00000000000
--- a/src/libstd/os/nacl/raw.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Nacl-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(since = "1.8.0",
-                    reason = "these type aliases are no longer supported by \
-                              the standard library, the `libc` crate on \
-                              crates.io should be used instead for the correct \
-                              definitions")]
-#![allow(deprecated)]
-
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_dev: dev_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ino: ino_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_mode: mode_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_nlink: nlink_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_uid: uid_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_gid: gid_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_rdev: dev_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_size: off_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_blksize: blksize_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_blocks: blkcnt_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_atime: time_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_atime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_mtime: time_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_mtime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ctime: time_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ctime_nsec: i64,
-}
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
index 3d9a06bedd5..00cf7eca75d 100644
--- a/src/libstd/sys/unix/env.rs
+++ b/src/libstd/sys/unix/env.rs
@@ -118,27 +118,6 @@ pub mod os {
     pub const EXE_EXTENSION: &'static str = "";
 }
 
-#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
-pub mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "nacl";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = ".nexe";
-    pub const EXE_EXTENSION: &'static str = "nexe";
-}
-#[cfg(all(target_os = "nacl", target_arch = "le32"))]
-pub mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "pnacl";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".pso";
-    pub const DLL_EXTENSION: &'static str = "pso";
-    pub const EXE_SUFFIX: &'static str = ".pexe";
-    pub const EXE_EXTENSION: &'static str = "pexe";
-}
-
 #[cfg(target_os = "haiku")]
 pub mod os {
     pub const FAMILY: &'static str = "unix";
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 1b3f1000b77..c2772e2e2cc 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -22,7 +22,6 @@ use libc;
 #[cfg(all(not(dox), target_os = "haiku"))]     pub use os::haiku as platform;
 #[cfg(all(not(dox), target_os = "ios"))]       pub use os::ios as platform;
 #[cfg(all(not(dox), target_os = "macos"))]     pub use os::macos as platform;
-#[cfg(all(not(dox), target_os = "nacl"))]      pub use os::nacl as platform;
 #[cfg(all(not(dox), target_os = "netbsd"))]    pub use os::netbsd as platform;
 #[cfg(all(not(dox), target_os = "openbsd"))]   pub use os::openbsd as platform;
 #[cfg(all(not(dox), target_os = "solaris"))]   pub use os::solaris as platform;
@@ -77,11 +76,11 @@ pub fn init() {
         reset_sigpipe();
     }
 
-    #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
+    #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
-    #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))]
+    #[cfg(any(target_os = "emscripten", target_os="fuchsia"))]
     unsafe fn reset_sigpipe() {}
 }
 
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 5ef98d24710..d8c30534eed 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -483,12 +483,10 @@ pub fn home_dir() -> Option<PathBuf> {
 
     #[cfg(any(target_os = "android",
               target_os = "ios",
-              target_os = "nacl",
               target_os = "emscripten"))]
     unsafe fn fallback() -> Option<OsString> { None }
     #[cfg(not(any(target_os = "android",
                   target_os = "ios",
-                  target_os = "nacl",
                   target_os = "emscripten")))]
     unsafe fn fallback() -> Option<OsString> {
         let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index 689ccd78524..383434b1cd8 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -464,7 +464,6 @@ mod tests {
     // test from being flaky we ignore it on macOS.
     #[test]
     #[cfg_attr(target_os = "macos", ignore)]
-    #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl.
     // When run under our current QEMU emulation test suite this test fails,
     // although the reason isn't very clear as to why. For now this test is
     // ignored there.
diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs
index 5d34da04446..a7a67ed36e8 100644
--- a/src/libstd/sys/unix/process/process_fuchsia.rs
+++ b/src/libstd/sys/unix/process/process_fuchsia.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use io;
-use libc;
+use libc::{self, size_t};
 use mem;
 use ptr;
 
@@ -148,8 +148,8 @@ impl Process {
         use sys::process::zircon::*;
 
         let mut proc_info: zx_info_process_t = Default::default();
-        let mut actual: zx_size_t = 0;
-        let mut avail: zx_size_t = 0;
+        let mut actual: size_t = 0;
+        let mut avail: size_t = 0;
 
         unsafe {
             zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
@@ -171,8 +171,8 @@ impl Process {
         use sys::process::zircon::*;
 
         let mut proc_info: zx_info_process_t = Default::default();
-        let mut actual: zx_size_t = 0;
-        let mut avail: zx_size_t = 0;
+        let mut actual: size_t = 0;
+        let mut avail: size_t = 0;
 
         unsafe {
             let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index 870db820027..743c458d580 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -184,8 +184,8 @@ impl Command {
             *sys::os::environ() = envp.as_ptr();
         }
 
-        // NaCl has no signal support.
-        #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))]
+        // emscripten has no signal support.
+        #[cfg(not(any(target_os = "emscripten")))]
         {
             use mem;
             // Reset signal handling so the child process starts in a
diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs
index b5ec11b40fd..90864e6ef3f 100644
--- a/src/libstd/sys/unix/process/zircon.rs
+++ b/src/libstd/sys/unix/process/zircon.rs
@@ -15,15 +15,13 @@ use io;
 use os::raw::c_char;
 use u64;
 
-use libc::{c_int, c_void};
+use libc::{c_int, c_void, size_t};
 
-pub type zx_handle_t = i32;
+pub type zx_handle_t = u32;
 pub type zx_vaddr_t = usize;
 pub type zx_rights_t = u32;
 pub type zx_status_t = i32;
 
-pub type zx_size_t = usize;
-
 pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
 
 pub type zx_time_t = u64;
@@ -115,36 +113,37 @@ extern {
                               pending: *mut zx_signals_t) -> zx_status_t;
 
     pub fn zx_object_get_info(handle: zx_handle_t, topic: u32, buffer: *mut c_void,
-                              buffer_size: zx_size_t, actual_size: *mut zx_size_t,
-                              avail: *mut zx_size_t) -> zx_status_t;
+                              buffer_size: size_t, actual_size: *mut size_t,
+                              avail: *mut size_t) -> zx_status_t;
 }
 
 // From `enum special_handles` in system/ulib/launchpad/launchpad.c
 // HND_LOADER_SVC = 0
 // HND_EXEC_VMO = 1
-pub const HND_SPECIAL_COUNT: usize = 2;
+// HND_SEGMENTS_VMAR = 2
+const HND_SPECIAL_COUNT: c_int = 3;
 
 #[repr(C)]
 pub struct launchpad_t {
     argc: u32,
     envc: u32,
     args: *const c_char,
-    args_len: usize,
+    args_len: size_t,
     env: *const c_char,
-    env_len: usize,
+    env_len: size_t,
 
     handles: *mut zx_handle_t,
     handles_info: *mut u32,
-    handle_count: usize,
-    handle_alloc: usize,
+    handle_count: size_t,
+    handle_alloc: size_t,
 
     entry: zx_vaddr_t,
     base: zx_vaddr_t,
     vdso_base: zx_vaddr_t,
 
-    stack_size: usize,
+    stack_size: size_t,
 
-    special_handles: [zx_handle_t; HND_SPECIAL_COUNT],
+    special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize],
     loader_message: bool,
 }
 
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index 617218fe7a5..8f78c2e6f59 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(target_os = "nacl", allow(dead_code))]
-
 /// Common code for printing the backtrace in the same way across the different
 /// supported platforms.
 
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 30887b16c60..07bbddc62b9 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -485,15 +485,17 @@ impl Builder {
 /// let (tx, rx) = channel();
 ///
 /// let sender = thread::spawn(move || {
-///     let _ = tx.send("Hello, thread".to_owned());
+///     tx.send("Hello, thread".to_owned())
+///         .expect("Unable to send on channel");
 /// });
 ///
 /// let receiver = thread::spawn(move || {
-///     println!("{}", rx.recv().unwrap());
+///     let value = rx.recv().expect("Unable to receive from channel");
+///     println!("{}", value);
 /// });
 ///
-/// let _ = sender.join();
-/// let _ = receiver.join();
+/// sender.join().expect("The sender thread has panicked");
+/// receiver.join().expect("The receiver thread has panicked");
 /// ```
 ///
 /// A thread can also return a value through its [`JoinHandle`], you can use
@@ -1192,7 +1194,7 @@ impl<T> JoinInner<T> {
 ///     });
 /// });
 ///
-/// let _ = original_thread.join();
+/// original_thread.join().expect("The thread being joined has panicked");
 /// println!("Original thread is joined.");
 ///
 /// // We make sure that the new thread has time to run, before the main
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 65dabe98a06..978e06c75dd 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3671,12 +3671,17 @@ impl<'a> Parser<'a> {
             None
         };
         let init = self.parse_initializer()?;
+        let hi = if self.token == token::Semi {
+            self.span
+        } else {
+            self.prev_span
+        };
         Ok(P(ast::Local {
             ty,
             pat,
             init,
             id: ast::DUMMY_NODE_ID,
-            span: lo.to(self.prev_span),
+            span: lo.to(hi),
             attrs,
         }))
     }
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 642eb285564..e8a1242c814 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -1554,16 +1554,14 @@ impl MetricMap {
 /// elimination.
 ///
 /// This function is a no-op, and does not even read from `dummy`.
-#[cfg(not(any(all(target_os = "nacl", target_arch = "le32"),
-              target_arch = "asmjs", target_arch = "wasm32")))]
+#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
 pub fn black_box<T>(dummy: T) -> T {
     // we need to "use" the argument in some way LLVM can't
     // introspect.
     unsafe { asm!("" : : "r"(&dummy)) }
     dummy
 }
-#[cfg(any(all(target_os = "nacl", target_arch = "le32"),
-          target_arch = "asmjs", target_arch = "wasm32"))]
+#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
 #[inline(never)]
 pub fn black_box<T>(dummy: T) -> T {
     dummy
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 2f966e5a1c5..e37f048dd47 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -26,7 +26,11 @@
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 
 #if LLVM_VERSION_GE(4, 0)
+#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
+#include "llvm/Transforms/IPO/FunctionImport.h"
+#include "llvm/Transforms/Utils/FunctionImportUtils.h"
+#include "llvm/LTO/LTO.h"
 #endif
 
 #include "llvm-c/Transforms/PassManagerBuilder.h"
@@ -102,6 +106,19 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
   PMB->add(Pass);
 }
 
+extern "C"
+bool LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
+  LLVMPassManagerBuilderRef PMBR,
+  LLVMPassManagerRef PMR
+) {
+#if LLVM_VERSION_GE(4, 0)
+  unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
+  return true;
+#else
+  return false;
+#endif
+}
+
 #ifdef LLVM_COMPONENT_X86
 #define SUBTARGET_X86 SUBTARGET(X86)
 #else
@@ -740,3 +757,447 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
   unwrap(M)->setPIELevel(PIELevel::Level::Large);
 #endif
 }
+
+extern "C" bool
+LLVMRustThinLTOAvailable() {
+#if LLVM_VERSION_GE(4, 0)
+  return true;
+#else
+  return false;
+#endif
+}
+
+#if LLVM_VERSION_GE(4, 0)
+
+// Here you'll find an implementation of ThinLTO as used by the Rust compiler
+// right now. This ThinLTO support is only enabled on "recent ish" versions of
+// LLVM, and otherwise it's just blanket rejected from other compilers.
+//
+// Most of this implementation is straight copied from LLVM. At the time of
+// this writing it wasn't *quite* suitable to reuse more code from upstream
+// for our purposes, but we should strive to upstream this support once it's
+// ready to go! I figure we may want a bit of testing locally first before
+// sending this upstream to LLVM. I hear though they're quite eager to receive
+// feedback like this!
+//
+// If you're reading this code and wondering "what in the world" or you're
+// working "good lord by LLVM upgrade is *still* failing due to these bindings"
+// then fear not! (ok maybe fear a little). All code here is mostly based
+// on `lib/LTO/ThinLTOCodeGenerator.cpp` in LLVM.
+//
+// You'll find that the general layout here roughly corresponds to the `run`
+// method in that file as well as `ProcessThinLTOModule`. Functions are
+// specifically commented below as well, but if you're updating this code
+// or otherwise trying to understand it, the LLVM source will be useful in
+// interpreting the mysteries within.
+//
+// Otherwise I'll apologize in advance, it probably requires a relatively
+// significant investment on your part to "truly understand" what's going on
+// here. Not saying I do myself, but it took me awhile staring at LLVM's source
+// and various online resources about ThinLTO to make heads or tails of all
+// this.
+
+extern "C" bool
+LLVMRustWriteThinBitcodeToFile(LLVMPassManagerRef PMR,
+                               LLVMModuleRef M,
+                               const char *BcFile) {
+  llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
+  std::error_code EC;
+  llvm::raw_fd_ostream bc(BcFile, EC, llvm::sys::fs::F_None);
+  if (EC) {
+    LLVMRustSetLastError(EC.message().c_str());
+    return false;
+  }
+  PM->add(createWriteThinLTOBitcodePass(bc));
+  PM->run(*unwrap(M));
+  delete PM;
+  return true;
+}
+
+// This is a shared data structure which *must* be threadsafe to share
+// read-only amongst threads. This also corresponds basically to the arguments
+// of the `ProcessThinLTOModule` function in the LLVM source.
+struct LLVMRustThinLTOData {
+  // The combined index that is the global analysis over all modules we're
+  // performing ThinLTO for. This is mostly managed by LLVM.
+  ModuleSummaryIndex Index;
+
+  // All modules we may look at, stored as in-memory serialized versions. This
+  // is later used when inlining to ensure we can extract any module to inline
+  // from.
+  StringMap<MemoryBufferRef> ModuleMap;
+
+  // A set that we manage of everything we *don't* want internalized. Note that
+  // this includes all transitive references right now as well, but it may not
+  // always!
+  DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
+
+  // Not 100% sure what these are, but they impact what's internalized and
+  // what's inlined across modules, I believe.
+  StringMap<FunctionImporter::ImportMapTy> ImportLists;
+  StringMap<FunctionImporter::ExportSetTy> ExportLists;
+  StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+};
+
+// Just an argument to the `LLVMRustCreateThinLTOData` function below.
+struct LLVMRustThinLTOModule {
+  const char *identifier;
+  const char *data;
+  size_t len;
+};
+
+// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`, not sure what it
+// does.
+static const GlobalValueSummary *
+getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) {
+  auto StrongDefForLinker = llvm::find_if(
+      GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
+        auto Linkage = Summary->linkage();
+        return !GlobalValue::isAvailableExternallyLinkage(Linkage) &&
+               !GlobalValue::isWeakForLinker(Linkage);
+      });
+  if (StrongDefForLinker != GVSummaryList.end())
+    return StrongDefForLinker->get();
+
+  auto FirstDefForLinker = llvm::find_if(
+      GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
+        auto Linkage = Summary->linkage();
+        return !GlobalValue::isAvailableExternallyLinkage(Linkage);
+      });
+  if (FirstDefForLinker == GVSummaryList.end())
+    return nullptr;
+  return FirstDefForLinker->get();
+}
+
+// This is a helper function we added that isn't present in LLVM's source.
+//
+// The way LTO works in Rust is that we typically have a number of symbols that
+// we know ahead of time need to be preserved. We want to ensure that ThinLTO
+// doesn't accidentally internalize any of these and otherwise is always
+// ready to keep them linking correctly.
+//
+// This function will recursively walk the `GUID` provided and all of its
+// references, as specified in the `Index`. In other words, we're taking a
+// `GUID` as input, adding it to `Preserved`, and then taking all `GUID`
+// items that the input references and recursing.
+static void
+addPreservedGUID(const ModuleSummaryIndex &Index,
+                 DenseSet<GlobalValue::GUID> &Preserved,
+                 GlobalValue::GUID GUID) {
+  if (Preserved.count(GUID))
+    return;
+  Preserved.insert(GUID);
+
+  auto SummaryList = Index.findGlobalValueSummaryList(GUID);
+  if (SummaryList == Index.end())
+    return;
+  for (auto &Summary : SummaryList->second) {
+    for (auto &Ref : Summary->refs()) {
+      if (Ref.isGUID()) {
+        addPreservedGUID(Index, Preserved, Ref.getGUID());
+      } else {
+        auto Value = Ref.getValue();
+        addPreservedGUID(Index, Preserved, Value->getGUID());
+      }
+    }
+
+    GlobalValueSummary *GVSummary = Summary.get();
+    if (isa<FunctionSummary>(GVSummary)) {
+      FunctionSummary *FS = cast<FunctionSummary>(GVSummary);
+      for (auto &Call: FS->calls()) {
+        if (Call.first.isGUID()) {
+          addPreservedGUID(Index, Preserved, Call.first.getGUID());
+        } else {
+          auto Value = Call.first.getValue();
+          addPreservedGUID(Index, Preserved, Value->getGUID());
+        }
+      }
+      for (auto &GUID: FS->type_tests()) {
+        addPreservedGUID(Index, Preserved, GUID);
+      }
+    }
+  }
+}
+
+// The main entry point for creating the global ThinLTO analysis. The structure
+// here is basically the same as before threads are spawned in the `run`
+// function of `lib/LTO/ThinLTOCodeGenerator.cpp`.
+extern "C" LLVMRustThinLTOData*
+LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
+                          int num_modules,
+                          const char **preserved_symbols,
+                          int num_symbols) {
+  auto Ret = llvm::make_unique<LLVMRustThinLTOData>();
+
+  // Load each module's summary and merge it into one combined index
+  for (int i = 0; i < num_modules; i++) {
+    auto module = &modules[i];
+    StringRef buffer(module->data, module->len);
+    MemoryBufferRef mem_buffer(buffer, module->identifier);
+
+    Ret->ModuleMap[module->identifier] = mem_buffer;
+
+    Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr =
+      object::ModuleSummaryIndexObjectFile::create(mem_buffer);
+    if (!ObjOrErr) {
+      LLVMRustSetLastError(toString(ObjOrErr.takeError()).c_str());
+      return nullptr;
+    }
+    auto Index = (*ObjOrErr)->takeIndex();
+    Ret->Index.mergeFrom(std::move(Index), i);
+  }
+
+  // Collect for each module the list of function it defines (GUID -> Summary)
+  Ret->Index.collectDefinedGVSummariesPerModule(Ret->ModuleToDefinedGVSummaries);
+
+  // Convert the preserved symbols set from string to GUID, this is then needed
+  // for internalization. We use `addPreservedGUID` to include any transitively
+  // used symbol as well.
+  for (int i = 0; i < num_symbols; i++) {
+    addPreservedGUID(Ret->Index,
+                     Ret->GUIDPreservedSymbols,
+                     GlobalValue::getGUID(preserved_symbols[i]));
+  }
+
+  // Collect the import/export lists for all modules from the call-graph in the
+  // combined index
+  //
+  // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
+  computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+  ComputeCrossModuleImport(
+    Ret->Index,
+    Ret->ModuleToDefinedGVSummaries,
+    Ret->ImportLists,
+    Ret->ExportLists
+  );
+
+  // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
+  // impacts the caching.
+  //
+  // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
+  StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
+  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
+  for (auto &I : Ret->Index) {
+    if (I.second.size() > 1)
+      PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second);
+  }
+  auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
+    const auto &Prevailing = PrevailingCopy.find(GUID);
+    if (Prevailing == PrevailingCopy.end())
+      return true;
+    return Prevailing->second == S;
+  };
+  auto recordNewLinkage = [&](StringRef ModuleIdentifier,
+                              GlobalValue::GUID GUID,
+                              GlobalValue::LinkageTypes NewLinkage) {
+    ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
+  };
+  thinLTOResolveWeakForLinkerInIndex(Ret->Index, isPrevailing, recordNewLinkage);
+  auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
+    const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier);
+    return (ExportList != Ret->ExportLists.end() &&
+      ExportList->second.count(GUID)) ||
+      Ret->GUIDPreservedSymbols.count(GUID);
+  };
+  thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported);
+
+  return Ret.release();
+}
+
+extern "C" void
+LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
+  delete Data;
+}
+
+// Below are the various passes that happen *per module* when doing ThinLTO.
+//
+// In other words, these are the functions that are all run concurrently
+// with one another, one per module. The passes here correspond to the analysis
+// passes in `lib/LTO/ThinLTOCodeGenerator.cpp`, currently found in the
+// `ProcessThinLTOModule` function. Here they're split up into separate steps
+// so rustc can save off the intermediate bytecode between each step.
+
+extern "C" bool
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  if (renameModuleForThinLTO(Mod, Data->Index)) {
+    LLVMRustSetLastError("renameModuleForThinLTO failed");
+    return false;
+  }
+  return true;
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
+  thinLTOResolveWeakForLinkerModule(Mod, DefinedGlobals);
+  return true;
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
+  thinLTOInternalizeModule(Mod, DefinedGlobals);
+  return true;
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
+  auto Loader = [&](StringRef Identifier) {
+    const auto &Memory = Data->ModuleMap.lookup(Identifier);
+    auto &Context = Mod.getContext();
+    return getLazyBitcodeModule(Memory, Context, true, true);
+  };
+  FunctionImporter Importer(Data->Index, Loader);
+  Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
+  if (!Result) {
+    LLVMRustSetLastError(toString(Result.takeError()).c_str());
+    return false;
+  }
+  return true;
+}
+
+// This struct and various functions are sort of a hack right now, but the
+// problem is that we've got in-memory LLVM modules after we generate and
+// optimize all codegen-units for one compilation in rustc. To be compatible
+// with the LTO support above we need to serialize the modules plus their
+// ThinLTO summary into memory.
+//
+// This structure is basically an owned version of a serialize module, with
+// a ThinLTO summary attached.
+struct LLVMRustThinLTOBuffer {
+  std::string data;
+};
+
+extern "C" LLVMRustThinLTOBuffer*
+LLVMRustThinLTOBufferCreate(LLVMModuleRef M) {
+  auto Ret = llvm::make_unique<LLVMRustThinLTOBuffer>();
+  {
+    raw_string_ostream OS(Ret->data);
+    {
+      legacy::PassManager PM;
+      PM.add(createWriteThinLTOBitcodePass(OS));
+      PM.run(*unwrap(M));
+    }
+  }
+  return Ret.release();
+}
+
+extern "C" void
+LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) {
+  delete Buffer;
+}
+
+extern "C" const void*
+LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) {
+  return Buffer->data.data();
+}
+
+extern "C" size_t
+LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
+  return Buffer->data.length();
+}
+
+// This is what we used to parse upstream bitcode for actual ThinLTO
+// processing.  We'll call this once per module optimized through ThinLTO, and
+// it'll be called concurrently on many threads.
+extern "C" LLVMModuleRef
+LLVMRustParseBitcodeForThinLTO(LLVMContextRef Context,
+                               const char *data,
+                               size_t len,
+                               const char *identifier) {
+  StringRef Data(data, len);
+  MemoryBufferRef Buffer(Data, identifier);
+  unwrap(Context)->enableDebugTypeODRUniquing();
+  Expected<std::unique_ptr<Module>> SrcOrError =
+      parseBitcodeFile(Buffer, *unwrap(Context));
+  if (!SrcOrError) {
+    LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
+    return nullptr;
+  }
+  return wrap(std::move(*SrcOrError).release());
+}
+
+#else
+
+extern "C" bool
+LLVMRustWriteThinBitcodeToFile(LLVMPassManagerRef PMR,
+                               LLVMModuleRef M,
+                               const char *BcFile) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+struct LLVMRustThinLTOData {
+};
+
+struct LLVMRustThinLTOModule {
+};
+
+extern "C" LLVMRustThinLTOData*
+LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
+                          int num_modules,
+                          const char **preserved_symbols,
+                          int num_symbols) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" void
+LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+struct LLVMRustThinLTOBuffer {
+};
+
+extern "C" LLVMRustThinLTOBuffer*
+LLVMRustThinLTOBufferCreate(LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" void
+LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" const void*
+LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" size_t
+LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" LLVMModuleRef
+LLVMRustParseBitcodeForThinLTO(LLVMContextRef Context,
+                               const char *data,
+                               size_t len,
+                               const char *identifier) {
+  llvm_unreachable("ThinLTO not available");
+}
+#endif // LLVM_VERSION_GE(4, 0)
diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
index d8e6028b799..bd1325e7501 100644
--- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -11,7 +11,7 @@
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic0[Internal]
 struct StructWithDtor(u32);
 
 impl Drop for StructWithDtor {
@@ -22,7 +22,7 @@ impl Drop for StructWithDtor {
 //~ TRANS_ITEM fn drop_in_place_intrinsic::main[0]
 fn main() {
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
     drop_slice_in_place(&x);
@@ -34,7 +34,7 @@ fn drop_slice_in_place(x: &[StructWithDtor]) {
         // This is the interesting thing in this test case: Normally we would
         // not have drop-glue for the unsized [StructWithDtor]. This has to be
         // generated though when the drop_in_place() intrinsic is used.
-        //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic.cgu-0[Internal]
+        //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic0[Internal]
         ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]);
     }
 }
diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs
index 06e02b10015..108a8b570de 100644
--- a/src/test/codegen-units/item-collection/generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs
@@ -45,7 +45,7 @@ enum EnumNoDrop<T1, T2> {
 struct NonGenericNoDrop(i32);
 
 struct NonGenericWithDrop(i32);
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue0[Internal]
 
 impl Drop for NonGenericWithDrop {
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
@@ -54,11 +54,11 @@ impl Drop for NonGenericWithDrop {
 
 //~ TRANS_ITEM fn generic_drop_glue::main[0]
 fn main() {
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
     let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
 
@@ -67,17 +67,17 @@ fn main() {
 
     // This is supposed to generate drop-glue because it contains a field that
     // needs to be dropped.
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue0[Internal]
     let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<i32, i64>
     let _ = match EnumWithDrop::A::<i32, i64>(0) {
         EnumWithDrop::A(x) => x,
         EnumWithDrop::B(x) => x as i32
     };
 
-    //~TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue.cgu-0[Internal]
+    //~TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<f64, f32>
     let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
         EnumWithDrop::A(x) => x,
diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
index 9c6bdb6624e..875cacb3907 100644
--- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -31,13 +31,13 @@ impl<T> Trait for Struct<T> {
 fn main() {
     let s1 = Struct { _a: 0u32 };
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable0[Internal]
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u32>
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u32>
     let _ = &s1 as &Trait;
 
     let s1 = Struct { _a: 0u64 };
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable0[Internal]
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u64>
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u64>
     let _ = &s1 as &Trait;
diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
index 5f70ff396dd..a6081b2c5eb 100644
--- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -13,7 +13,7 @@
 
 #![deny(dead_code)]
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue0[Internal]
 struct StructWithDrop {
     x: i32
 }
@@ -27,7 +27,7 @@ struct StructNoDrop {
     x: i32
 }
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue0[Internal]
 enum EnumWithDrop {
     A(i32)
 }
diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
index e41cb34eec6..8eef5f00f2a 100644
--- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
@@ -13,11 +13,11 @@
 
 #![deny(dead_code)]
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue0[Internal]
 struct Root(Intermediate);
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue0[Internal]
 struct Intermediate(Leaf);
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue0[Internal]
 struct Leaf;
 
 impl Drop for Leaf {
@@ -38,15 +38,15 @@ fn main() {
 
     let _ = Root(Intermediate(Leaf));
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue0[Internal]
     //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<u32>
     let _ = RootGen(IntermediateGen(LeafGen(0u32)));
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue0[Internal]
     //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
     let _ = RootGen(IntermediateGen(LeafGen(0i16)));
 }
diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
index 39043cf87cb..7edb1c14525 100644
--- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
@@ -13,7 +13,7 @@
 
 #![deny(dead_code)]
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue0[Internal]
 struct Dropped;
 
 impl Drop for Dropped {
@@ -23,10 +23,10 @@ impl Drop for Dropped {
 
 //~ TRANS_ITEM fn tuple_drop_glue::main[0]
 fn main() {
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal]
     let x = (0u32, Dropped);
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal]
     let x = (0i16, (Dropped, true));
 }
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index de7613741b2..cf0c6643238 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -57,13 +57,13 @@ fn main()
 {
     // simple case
     let bool_sized = &true;
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0]
     let _bool_unsized = bool_sized as &Trait;
 
     let char_sized = &'a';
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0]
     let _char_unsized = char_sized as &Trait;
 
@@ -73,13 +73,13 @@ fn main()
         _b: 2,
         _c: 3.0f64
     };
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0]
     let _struct_unsized = struct_sized as &Struct<Trait>;
 
     // custom coercion
     let wrapper_sized = Wrapper(&0u32);
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0]
     let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs b/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs
index 3098807f272..fcdcf198c28 100644
--- a/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs
+++ b/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs
@@ -8,12 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Check that we check fns appearing in constant declarations.
 // Issue #22382.
 
 const MOVE: fn(&String) -> String = {
     fn broken(x: &String) -> String {
-        return *x //~ ERROR cannot move
+        return *x //[ast]~ ERROR cannot move out of borrowed content [E0507]
+                  //[mir]~^ ERROR (Ast) [E0507]
+                  //[mir]~| ERROR (Mir) [E0507]
     }
     broken
 };
diff --git a/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs
index ec505faf885..99b5ef794c2 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs
@@ -8,19 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 fn with<F>(f: F) where F: FnOnce(&String) {}
 
 fn arg_item(&_x: &String) {}
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 
 fn arg_closure() {
     with(|&_x| ())
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 }
 
 fn let_pat() {
     let &_x = &"hi".to_string();
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 }
 
 pub fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
index bf4c7474136..c7e1ea1b758 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
@@ -8,9 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 use std::rc::Rc;
 
 pub fn main() {
     let _x = Rc::new(vec![1, 2]).into_iter();
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs
index 8b83b945fd1..9e8021fd108 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Ensure that moves out of static items is forbidden
 
 struct Foo {
@@ -22,5 +25,7 @@ fn test(f: Foo) {
 }
 
 fn main() {
-    test(BAR); //~ ERROR cannot move out of static item
+    test(BAR); //[ast]~ ERROR cannot move out of static item [E0507]
+               //[mir]~^ ERROR (Ast) [E0507]
+               //[mir]~| ERROR (Mir) [E0507]
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
index 16302d276ce..982f31b1341 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 struct S {f:String}
 impl Drop for S {
     fn drop(&mut self) { println!("{}", self.f); }
@@ -16,17 +19,23 @@ impl Drop for S {
 fn move_in_match() {
     match (S {f:"foo".to_string()}) {
         S {f:_s} => {}
-        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
+        //[mir]~^^ ERROR (Ast) [E0509]
+        //[mir]~|  ERROR (Mir) [E0509]
     }
 }
 
 fn move_in_let() {
     let S {f:_s} = S {f:"foo".to_string()};
-    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+    //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn move_in_fn_arg(S {f:_s}: S) {
-    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+    //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
index c364788a9cc..4a1828c6958 100644
--- a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Issue 4691: Ensure that functional-struct-update can only copy, not
 // move, when the struct implements Drop.
 
@@ -20,12 +23,16 @@ impl Drop for T { fn drop(&mut self) { } }
 
 fn f(s0:S) {
     let _s2 = S{a: 2, ..s0};
-    //~^ error: cannot move out of type `S`, which implements the `Drop` trait
+    //[ast]~^ error: cannot move out of type `S`, which implements the `Drop` trait
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn g(s0:T) {
     let _s2 = T{a: 2, ..s0};
-    //~^ error: cannot move out of type `T`, which implements the `Drop` trait
+    //[ast]~^ error: cannot move out of type `T`, which implements the `Drop` trait
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
index 3c1980e5b36..7f3120cc83e 100644
--- a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
+++ b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Regression test for #38520. Check that moves of `Foo` are not
 // permitted as `Foo` is not copy (even in a static/const
 // initializer).
@@ -21,8 +24,12 @@ const fn get(x: Foo) -> usize {
 }
 
 const X: Foo = Foo(22);
-static Y: usize = get(*&X); //~ ERROR E0507
-const Z: usize = get(*&X); //~ ERROR E0507
+static Y: usize = get(*&X); //[ast]~ ERROR E0507
+                            //[mir]~^ ERROR (Ast) [E0507]
+                            //[mir]~| ERROR (Mir) [E0507]
+const Z: usize = get(*&X); //[ast]~ ERROR E0507
+                           //[mir]~^ ERROR (Ast) [E0507]
+                           //[mir]~| ERROR (Mir) [E0507]
 
 fn main() {
 }
diff --git a/src/test/compile-fail/issue-30355.rs b/src/test/compile-fail/issue-30355.rs
new file mode 100644
index 00000000000..ee19d040318
--- /dev/null
+++ b/src/test/compile-fail/issue-30355.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct X([u8]);
+
+pub static Y: &'static X = {
+    const Y: &'static [u8] = b"";
+    &X(*Y)
+    //~^ ERROR cannot move out
+    //~^^ ERROR cannot move a
+    //~^^^ ERROR cannot move a
+};
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-33241.rs b/src/test/compile-fail/issue-33241.rs
new file mode 100644
index 00000000000..6a411b4c59c
--- /dev/null
+++ b/src/test/compile-fail/issue-33241.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+
+use std::fmt;
+
+// CoerceUnsized is not implemented for tuples. You can still create
+// an unsized tuple by transmuting a trait object.
+fn any<T>() -> T { unreachable!() }
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+    let t: &(u8, fmt::Debug) = any();
+    println!("{:?}", &t.1);
+}
diff --git a/src/test/compile-fail/issue-37887.rs b/src/test/compile-fail/issue-37887.rs
new file mode 100644
index 00000000000..f120bbbfc9f
--- /dev/null
+++ b/src/test/compile-fail/issue-37887.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    extern crate libc; //~ ERROR use of unstable
+    use libc::*; //~ ERROR unresolved import
+}
diff --git a/src/test/compile-fail/issue-44578.rs b/src/test/compile-fail/issue-44578.rs
new file mode 100644
index 00000000000..a6ae21c3b54
--- /dev/null
+++ b/src/test/compile-fail/issue-44578.rs
@@ -0,0 +1,34 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+    const AMT: usize;
+}
+
+enum Bar<A, B> {
+    First(A),
+    Second(B),
+}
+
+impl<A: Foo, B: Foo> Foo for Bar<A, B> {
+    const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ ERROR constant evaluation
+}
+
+impl Foo for u8 {
+    const AMT: usize = 1;
+}
+
+impl Foo for u16 {
+    const AMT: usize = 2;
+}
+
+fn main() {
+    println!("{}", <Bar<u16, u8> as Foo>::AMT);
+}
diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs
index ec044225b83..d2ca65775a4 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -30,7 +30,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node12.EraseRegions.after.mir
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
 //         return;
 //     }
 // END rustc.node12.EraseRegions.after.mir
@@ -57,7 +57,7 @@ fn main() {
 // START rustc.node50.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:11) => validate_1/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:11) => validate_1/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs
index 571ed425402..d240b51e222 100644
--- a/src/test/mir-opt/validate_4.rs
+++ b/src/test/mir-opt/validate_4.rs
@@ -48,8 +48,8 @@ fn main() {
 // START rustc.node22.EraseRegions.after.mir
 // fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         (*_3) = const 23i32;
@@ -61,8 +61,8 @@ fn main() {
 // START rustc.node31.EraseRegions.after.mir
 // fn test(_1: &ReErased mut i32) -> () {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]);
 //         _3 = const write_42(_4) -> bb1;
 //     }
 //     bb1: {
@@ -74,8 +74,8 @@ fn main() {
 // START rustc.node60.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _0 = const write_42(_4) -> bb1;
 //     }
diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs
index ff0c781d1e3..e1eeb2102d1 100644
--- a/src/test/mir-opt/validate_5.rs
+++ b/src/test/mir-opt/validate_5.rs
@@ -36,7 +36,7 @@ fn main() {
 // START rustc.node17.EraseRegions.after.mir
 // fn test(_1: &ReErased mut i32) -> () {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_5/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_5[8cd8]::test[0] }, BrAnon(0)) mut i32]);
 //         Validate(Release, [_3: bool, _4: *mut i32]);
 //         _3 = const write_42(_4) -> bb1;
 //     }
@@ -45,7 +45,7 @@ fn main() {
 // START rustc.node46.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_5/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_5/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
diff --git a/src/test/run-make/extra-filename-with-temp-outputs/Makefile b/src/test/run-make/extra-filename-with-temp-outputs/Makefile
index d33c18a6f3c..13ca397eaf2 100644
--- a/src/test/run-make/extra-filename-with-temp-outputs/Makefile
+++ b/src/test/run-make/extra-filename-with-temp-outputs/Makefile
@@ -2,5 +2,5 @@
 
 all:
 	$(RUSTC) -C extra-filename=bar foo.rs -C save-temps
-	rm $(TMPDIR)/foobar.0.o
+	rm $(TMPDIR)/foobar.foo0.rust-cgu.o
 	rm $(TMPDIR)/$(call BIN,foobar)
diff --git a/src/test/run-make/sepcomp-cci-copies/Makefile b/src/test/run-make/sepcomp-cci-copies/Makefile
index 189088219d5..8324a074d6c 100644
--- a/src/test/run-make/sepcomp-cci-copies/Makefile
+++ b/src/test/run-make/sepcomp-cci-copies/Makefile
@@ -6,4 +6,4 @@
 all:
 	$(RUSTC) cci_lib.rs
 	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ .*cci_fn)" -eq "2" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*cci_fn)" -eq "2" ]
diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile
index 720dfff2c04..6dc837b8a78 100644
--- a/src/test/run-make/sepcomp-inlining/Makefile
+++ b/src/test/run-make/sepcomp-inlining/Makefile
@@ -8,7 +8,7 @@
 
 all:
 	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]
diff --git a/src/test/run-make/sepcomp-separate/Makefile b/src/test/run-make/sepcomp-separate/Makefile
index a475bdfd74a..5b8bdb0fad8 100644
--- a/src/test/run-make/sepcomp-separate/Makefile
+++ b/src/test/run-make/sepcomp-separate/Makefile
@@ -6,4 +6,4 @@
 
 all:
 	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ .*magic_fn)" -eq "3" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*magic_fn)" -eq "3" ]
diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
index 8ba38875eff..52a8652e65b 100644
--- a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:attr-on-trait.rs
+// ignore-stage1
 
 #![feature(proc_macro)]
 
diff --git a/src/libstd/os/nacl/mod.rs b/src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs
index 7dfa2eabe3e..ccbb0e7a718 100644
--- a/src/libstd/os/nacl/mod.rs
+++ b/src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,9 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Nacl-specific definitions
+// no-prefer-dynamic
 
-#![stable(feature = "raw_ext", since = "1.1.0")]
+#![crate_type = "rlib"]
 
-pub mod raw;
-pub mod fs;
+pub fn bar() -> u32 {
+    3
+}
diff --git a/src/test/run-pass/thin-lto-inlines.rs b/src/test/run-pass/thin-lto-inlines.rs
new file mode 100644
index 00000000000..3135a682d86
--- /dev/null
+++ b/src/test/run-pass/thin-lto-inlines.rs
@@ -0,0 +1,39 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// min-llvm-version 4.0
+// ignore-emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+    bar::bar()
+}
+
+mod bar {
+    pub fn bar() -> u32 {
+        3
+    }
+}
+
+fn main() {
+    println!("{} {}", foo(), bar::bar());
+
+    unsafe {
+        let foo = foo as usize as *const u8;
+        let bar = bar::bar as usize as *const u8;
+
+        assert_eq!(*foo, *bar);
+    }
+}
diff --git a/src/test/run-pass/thin-lto-inlines2.rs b/src/test/run-pass/thin-lto-inlines2.rs
new file mode 100644
index 00000000000..ed899d2b115
--- /dev/null
+++ b/src/test/run-pass/thin-lto-inlines2.rs
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
+// aux-build:thin-lto-inlines-aux.rs
+// min-llvm-version 4.0
+// no-prefer-dynamic
+// ignore-emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+    bar::bar()
+}
+
+fn main() {
+    println!("{} {}", foo(), bar::bar());
+
+    unsafe {
+        let foo = foo as usize as *const u8;
+        let bar = bar::bar as usize as *const u8;
+
+        assert_eq!(*foo, *bar);
+    }
+}
+
diff --git a/src/test/rustdoc/fn-pointer-arg-name.rs b/src/test/rustdoc/fn-pointer-arg-name.rs
new file mode 100644
index 00000000000..af87f1b4669
--- /dev/null
+++ b/src/test/rustdoc/fn-pointer-arg-name.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
+pub fn f(callback: fn(len: usize, foo: u32)) {}
diff --git a/src/test/ui/issue-36400.rs b/src/test/ui/issue-36400.rs
new file mode 100644
index 00000000000..c0aec5b4296
--- /dev/null
+++ b/src/test/ui/issue-36400.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn f(x: &mut u32) {}
+
+fn main() {
+    let x = Box::new(3);
+    f(&mut *x);
+}
diff --git a/src/test/ui/issue-36400.stderr b/src/test/ui/issue-36400.stderr
new file mode 100644
index 00000000000..69e9c455f35
--- /dev/null
+++ b/src/test/ui/issue-36400.stderr
@@ -0,0 +1,10 @@
+error[E0596]: cannot borrow immutable `Box` content `*x` as mutable
+  --> $DIR/issue-36400.rs:15:12
+   |
+14 |     let x = Box::new(3);
+   |         - consider changing this to `mut x`
+15 |     f(&mut *x);
+   |            ^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index db957a7a0fc..daeac35a017 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -83,6 +83,7 @@ static TARGETS: &'static [&'static str] = &[
     "powerpc64le-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
+    "sparcv9-sun-solaris",
     "wasm32-unknown-emscripten",
     "x86_64-linux-android",
     "x86_64-apple-darwin",
@@ -90,6 +91,7 @@ static TARGETS: &'static [&'static str] = &[
     "x86_64-pc-windows-gnu",
     "x86_64-pc-windows-msvc",
     "x86_64-rumprun-netbsd",
+    "x86_64-sun-solaris",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-fuchsia",
     "x86_64-unknown-linux-gnu",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index bb9bf57d55e..19195838791 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -567,6 +567,19 @@ impl Config {
             None
         }
     }
+
+    pub fn find_rust_src_root(&self) -> Option<PathBuf> {
+        let mut path = self.src_base.clone();
+        let path_postfix = Path::new("src/etc/lldb_batchmode.py");
+
+        while path.pop() {
+            if path.join(&path_postfix).is_file() {
+                return Some(path);
+            }
+        }
+
+        None
+    }
 }
 
 pub fn lldb_version_to_int(version_string: &str) -> isize {
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 26c447d01d3..306497da9e3 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -489,15 +489,28 @@ fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf {
 }
 
 fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> bool {
+    let rust_src_dir = config.find_rust_src_root().expect(
+        "Could not find Rust source root",
+    );
     let stamp = mtime(&stamp(config, testpaths));
-    let mut inputs = vec![
-        mtime(&testpaths.file),
-        mtime(&config.rustc_path),
-    ];
+    let mut inputs = vec![mtime(&testpaths.file), mtime(&config.rustc_path)];
     for aux in props.aux.iter() {
-        inputs.push(mtime(&testpaths.file.parent().unwrap()
-                                         .join("auxiliary")
-                                         .join(aux)));
+        inputs.push(mtime(
+            &testpaths.file.parent().unwrap().join("auxiliary").join(
+                aux,
+            ),
+        ));
+    }
+    // Relevant pretty printer files
+    let pretty_printer_files = [
+        "src/etc/debugger_pretty_printers_common.py",
+        "src/etc/gdb_load_rust_pretty_printers.py",
+        "src/etc/gdb_rust_pretty_printing.py",
+        "src/etc/lldb_batchmode.py",
+        "src/etc/lldb_rust_formatters.py",
+    ];
+    for pretty_printer_file in &pretty_printer_files {
+        inputs.push(mtime(&rust_src_dir.join(pretty_printer_file)));
     }
     for lib in config.run_lib_path.read_dir().unwrap() {
         let lib = lib.unwrap();
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 10ef326d9db..870e08cc6e5 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -571,9 +571,10 @@ actual:\n\
                 }
             }
 
-            _=> {
-                let rust_src_root = self.find_rust_src_root()
-                                        .expect("Could not find Rust source root");
+            _ => {
+                let rust_src_root = self.config.find_rust_src_root().expect(
+                    "Could not find Rust source root",
+                );
                 let rust_pp_module_rel_path = Path::new("./src/etc");
                 let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
                                                            .to_str()
@@ -664,19 +665,6 @@ actual:\n\
         self.check_debugger_output(&debugger_run_result, &check_lines);
     }
 
-    fn find_rust_src_root(&self) -> Option<PathBuf> {
-        let mut path = self.config.src_base.clone();
-        let path_postfix = Path::new("src/etc/lldb_batchmode.py");
-
-        while path.pop() {
-            if path.join(&path_postfix).is_file() {
-                return Some(path);
-            }
-        }
-
-        None
-    }
-
     fn run_debuginfo_lldb_test(&self) {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
@@ -735,7 +723,9 @@ actual:\n\
         script_str.push_str("version\n");
 
         // Switch LLDB into "Rust mode"
-        let rust_src_root = self.find_rust_src_root().expect("Could not find Rust source root");
+        let rust_src_root = self.config.find_rust_src_root().expect(
+            "Could not find Rust source root",
+        );
         let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
         let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
                                                    .to_str()
@@ -1717,11 +1707,13 @@ actual:\n\
         if self.props.check_test_line_numbers_match {
             self.check_rustdoc_test_option(proc_res);
         } else {
-            let root = self.find_rust_src_root().unwrap();
-            let res = self.cmd2procres(Command::new(&self.config.docck_python)
-                                       .arg(root.join("src/etc/htmldocck.py"))
-                                       .arg(out_dir)
-                                       .arg(&self.testpaths.file));
+            let root = self.config.find_rust_src_root().unwrap();
+            let res = self.cmd2procres(
+                Command::new(&self.config.docck_python)
+                    .arg(root.join("src/etc/htmldocck.py"))
+                    .arg(out_dir)
+                    .arg(&self.testpaths.file),
+            );
             if !res.status.success() {
                 self.fatal_proc_rec("htmldocck failed!", &res);
             }