diff --git a/.gitignore b/.gitignore
index ff839c34df1a7..b54bab177d0ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,7 @@
 .hg/
 .hgignore
 .idea
+*.iml
 __pycache__/
 *.py[cod]
 *$py.class
diff --git a/.gitmodules b/.gitmodules
index 1ef3c086a1c23..6244b3c095186 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,9 +2,6 @@
 	path = src/llvm
 	url = https://github.com/rust-lang/llvm.git
 	branch = master
-[submodule "src/compiler-rt"]
-	path = src/compiler-rt
-	url = https://github.com/rust-lang/compiler-rt.git
 [submodule "src/rt/hoedown"]
 	path = src/rt/hoedown
 	url = https://github.com/rust-lang/hoedown.git
@@ -33,3 +30,6 @@
 [submodule "src/tools/rls"]
 	path = src/tools/rls
 	url = https://github.com/rust-lang-nursery/rls.git
+[submodule "src/libcompiler_builtins"]
+	path = src/libcompiler_builtins
+	url = https://github.com/rust-lang-nursery/compiler-builtins
diff --git a/README.md b/README.md
index 0b209fd3e9492..a1f018610753c 100644
--- a/README.md
+++ b/README.md
@@ -40,8 +40,9 @@ Read ["Installation"] from [The Book].
 
     > ***Note:*** Install locations can be adjusted by copying the config file
     > from `./src/bootstrap/config.toml.example` to `./config.toml`, and
-    > adjusting the `prefix` option under `[install]`. Various other options are
-    > also supported, and are documented in the config file.
+    > adjusting the `prefix` option under `[install]`. Various other options, such
+    > as enabling debug information, are also supported, and are documented in
+    > the config file.
 
     When complete, `sudo ./x.py install` will place several programs into
     `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 2d42903ad0a7d..28c4d2e981938 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -43,6 +43,8 @@ dependencies = [
 name = "alloc_jemalloc"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
+ "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "core 0.0.0",
  "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -53,6 +55,7 @@ dependencies = [
 name = "alloc_system"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "core 0.0.0",
  "libc 0.0.0",
 ]
@@ -273,7 +276,6 @@ dependencies = [
 name = "compiler_builtins"
 version = "0.0.0"
 dependencies = [
- "build_helper 0.1.0",
  "core 0.0.0",
  "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -883,14 +885,6 @@ name = "proc_macro"
 version = "0.0.0"
 dependencies = [
  "syntax 0.0.0",
-]
-
-[[package]]
-name = "proc_macro_plugin"
-version = "0.0.0"
-dependencies = [
- "rustc_plugin 0.0.0",
- "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
 
@@ -1127,10 +1121,21 @@ name = "rustc-serialize"
 version = "0.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "rustc_allocator"
+version = "0.0.0"
+dependencies = [
+ "rustc 0.0.0",
+ "rustc_errors 0.0.0",
+ "syntax 0.0.0",
+ "syntax_pos 0.0.0",
+]
+
 [[package]]
 name = "rustc_asan"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1203,8 +1208,8 @@ dependencies = [
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc_macro_plugin 0.0.0",
  "rustc 0.0.0",
+ "rustc_allocator 0.0.0",
  "rustc_back 0.0.0",
  "rustc_borrowck 0.0.0",
  "rustc_const_eval 0.0.0",
@@ -1273,6 +1278,7 @@ dependencies = [
 name = "rustc_lsan"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1317,6 +1323,7 @@ dependencies = [
 name = "rustc_msan"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1399,6 +1406,7 @@ dependencies = [
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_allocator 0.0.0",
  "rustc_back 0.0.0",
  "rustc_bitflags 0.0.0",
  "rustc_const_math 0.0.0",
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 8c6eaee24f294..497a5ab6c536c 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -75,16 +75,11 @@ fn main() {
         Err(_) => 0,
     };
 
-    // Build scripts always use the snapshot compiler which is guaranteed to be
-    // able to produce an executable, whereas intermediate compilers may not
-    // have the standard library built yet and may not be able to produce an
-    // executable. Otherwise we just use the standard compiler we're
-    // bootstrapping with.
-    //
-    // Also note that cargo will detect the version of the compiler to trigger
-    // a rebuild when the compiler changes. If this happens, we want to make
-    // sure to use the actual compiler instead of the snapshot compiler becase
-    // that's the one that's actually changing.
+    // Use a different compiler for build scripts, since there may not yet be a
+    // libstd for the real compiler to use. However, if Cargo is attempting to
+    // determine the version of the compiler, the real compiler needs to be
+    // used. Currently, these two states are differentiated based on whether
+    // --target and -vV is/isn't passed.
     let (rustc, libdir) = if target.is_none() && version.is_none() {
         ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
     } else {
@@ -142,6 +137,11 @@ fn main() {
             }
         }
 
+        let crate_name = args.windows(2)
+            .find(|a| &*a[0] == "--crate-name")
+            .unwrap();
+        let crate_name = &*crate_name[1];
+
         // If we're compiling specifically the `panic_abort` crate then we pass
         // the `-C panic=abort` option. Note that we do not do this for any
         // other crate intentionally as this is the only crate for now that we
@@ -150,9 +150,7 @@ fn main() {
         // This... is a bit of a hack how we detect this. Ideally this
         // information should be encoded in the crate I guess? Would likely
         // require an RFC amendment to RFC 1513, however.
-        let is_panic_abort = args.windows(2)
-            .any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort");
-        if is_panic_abort {
+        if crate_name == "panic_abort" {
             cmd.arg("-C").arg("panic=abort");
         }
 
@@ -167,7 +165,15 @@ fn main() {
             Ok(s) => if s == "true" { "y" } else { "n" },
             Err(..) => "n",
         };
-        cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
+
+        // The compiler builtins are pretty sensitive to symbols referenced in
+        // libcore and such, so we never compile them with debug assertions.
+        if crate_name == "compiler_builtins" {
+            cmd.arg("-C").arg("debug-assertions=no");
+        } else {
+            cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
+        }
+
         if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
             cmd.arg("-C").arg(format!("codegen-units={}", s));
         }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index eaf2a40f2fad4..ebc4c2fdf7bf2 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -583,7 +583,7 @@ def update_submodules(self):
                                (self.get_toml('jemalloc') or
                                 self.get_mk('CFG_JEMALLOC_ROOT'))))]
         run(["git", "submodule", "update",
-             "--init"] + submodules,
+             "--init", "--recursive"] + submodules,
             cwd=self.rust_root, verbose=self.verbose)
         run(["git", "submodule", "-q", "foreach", "git",
              "reset", "-q", "--hard"],
diff --git a/src/bootstrap/cc.rs b/src/bootstrap/cc.rs
index 54c8194678e61..7c7161916ee2c 100644
--- a/src/bootstrap/cc.rs
+++ b/src/bootstrap/cc.rs
@@ -42,10 +42,13 @@ use config::Target;
 pub fn find(build: &mut Build) {
     // For all targets we're going to need a C compiler for building some shims
     // and such as well as for being a linker for Rust code.
-    for target in build.config.target.iter() {
+    //
+    // This includes targets that aren't necessarily passed on the commandline
+    // (FIXME: Perhaps it shouldn't?)
+    for target in &build.config.target {
         let mut cfg = gcc::Config::new();
         cfg.cargo_metadata(false).opt_level(0).debug(false)
-           .target(target).host(&build.config.build);
+           .target(target).host(&build.build);
 
         let config = build.config.target_config.get(target);
         if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
@@ -64,10 +67,13 @@ pub fn find(build: &mut Build) {
     }
 
     // For all host triples we need to find a C++ compiler as well
-    for host in build.config.host.iter() {
+    //
+    // This includes hosts that aren't necessarily passed on the commandline
+    // (FIXME: Perhaps it shouldn't?)
+    for host in &build.config.host {
         let mut cfg = gcc::Config::new();
         cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true)
-           .target(host).host(&build.config.build);
+           .target(host).host(&build.build);
         let config = build.config.target_config.get(host);
         if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
             cfg.compiler(cxx);
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index 4664b1f765e63..1153acfa57d39 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -23,12 +23,12 @@ use build_helper::output;
 use Build;
 
 // The version number
-pub const CFG_RELEASE_NUM: &'static str = "1.20.0";
+pub const CFG_RELEASE_NUM: &str = "1.20.0";
 
 // An optional number to put after the label, e.g. '.2' -> '-beta.2'
 // Be sure to make this starts with a dot to conform to semver pre-release
 // versions (section 9)
-pub const CFG_PRERELEASE_VERSION: &'static str = ".1";
+pub const CFG_PRERELEASE_VERSION: &str = ".1";
 
 pub struct GitInfo {
     inner: Option<Info>,
@@ -99,6 +99,10 @@ impl GitInfo {
             version.push_str(&inner.commit_date);
             version.push_str(")");
         }
-        return version
+        version
+    }
+
+    pub fn is_git(&self) -> bool {
+        self.inner.is_some()
     }
 }
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 277728b90b763..b3b5ae8d67d65 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -13,23 +13,22 @@
 //! This file implements the various regression test suites that we execute on
 //! our CI.
 
-extern crate build_helper;
-
 use std::collections::HashSet;
 use std::env;
+use std::iter;
 use std::fmt;
 use std::fs::{self, File};
 use std::path::{PathBuf, Path};
 use std::process::Command;
 use std::io::Read;
 
-use build_helper::output;
+use build_helper::{self, output};
 
 use {Build, Compiler, Mode};
 use dist;
 use util::{self, dylib_path, dylib_path_var, exe};
 
-const ADB_TEST_DIR: &'static str = "/data/tmp/work";
+const ADB_TEST_DIR: &str = "/data/tmp/work";
 
 /// The two modes of the test runner; tests or benchmarks.
 #[derive(Copy, Clone)]
@@ -60,7 +59,7 @@ impl fmt::Display for TestKind {
 }
 
 fn try_run(build: &Build, cmd: &mut Command) {
-    if build.flags.cmd.no_fail_fast() {
+    if !build.fail_fast {
         if !build.try_run(cmd) {
             let failures = build.delayed_failures.get();
             build.delayed_failures.set(failures + 1);
@@ -71,7 +70,7 @@ fn try_run(build: &Build, cmd: &mut Command) {
 }
 
 fn try_run_quiet(build: &Build, cmd: &mut Command) {
-    if build.flags.cmd.no_fail_fast() {
+    if !build.fail_fast {
         if !build.try_run_quiet(cmd) {
             let failures = build.delayed_failures.get();
             build.delayed_failures.set(failures + 1);
@@ -99,7 +98,7 @@ pub fn linkcheck(build: &Build, host: &str) {
 /// This tool in `src/tools` will check out a few Rust projects and run `cargo
 /// test` to ensure that we don't regress the test suites there.
 pub fn cargotest(build: &Build, stage: u32, host: &str) {
-    let ref compiler = Compiler::new(stage, host);
+    let compiler = Compiler::new(stage, host);
 
     // Note that this is a short, cryptic, and not scoped directory name. This
     // is currently to minimize the length of path on Windows where we otherwise
@@ -109,11 +108,11 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) {
 
     let _time = util::timeit();
     let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
-    build.prepare_tool_cmd(compiler, &mut cmd);
-    try_run(build, cmd.arg(&build.cargo)
+    build.prepare_tool_cmd(&compiler, &mut cmd);
+    try_run(build, cmd.arg(&build.initial_cargo)
                       .arg(&out_dir)
-                      .env("RUSTC", build.compiler_path(compiler))
-                      .env("RUSTDOC", build.rustdoc(compiler)));
+                      .env("RUSTC", build.compiler_path(&compiler))
+                      .env("RUSTDOC", build.rustdoc(&compiler)));
 }
 
 /// Runs `cargo test` for `cargo` packaged with Rust.
@@ -124,13 +123,12 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
     // and not RUSTC because the Cargo test suite has tests that will
     // fail if rustc is not spelled `rustc`.
     let path = build.sysroot(compiler).join("bin");
-    let old_path = ::std::env::var("PATH").expect("");
-    let sep = if cfg!(windows) { ";" } else {":" };
-    let ref newpath = format!("{}{}{}", path.display(), sep, old_path);
+    let old_path = env::var_os("PATH").unwrap_or_default();
+    let newpath = env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("");
 
     let mut cargo = build.cargo(compiler, Mode::Tool, host, "test");
     cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml"));
-    if build.flags.cmd.no_fail_fast() {
+    if !build.fail_fast {
         cargo.arg("--no-fail-fast");
     }
 
@@ -198,9 +196,9 @@ pub fn compiletest(build: &Build,
     cmd.arg("--mode").arg(mode);
     cmd.arg("--target").arg(target);
     cmd.arg("--host").arg(compiler.host);
-    cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
+    cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.build));
 
-    if let Some(nodejs) = build.config.nodejs.as_ref() {
+    if let Some(ref nodejs) = build.config.nodejs {
         cmd.arg("--nodejs").arg(nodejs);
     }
 
@@ -224,7 +222,7 @@ pub fn compiletest(build: &Build,
 
     cmd.arg("--docck-python").arg(build.python());
 
-    if build.config.build.ends_with("apple-darwin") {
+    if build.build.ends_with("apple-darwin") {
         // Force /usr/bin/python on macOS for LLDB tests because we're loading the
         // LLDB plugin's compiled module which only works with the system python
         // (namely not Homebrew-installed python)
@@ -251,7 +249,7 @@ pub fn compiletest(build: &Build,
 
     cmd.args(&build.flags.cmd.test_args());
 
-    if build.config.verbose() || build.flags.verbose() {
+    if build.is_verbose() {
         cmd.arg("--verbose");
     }
 
@@ -279,7 +277,7 @@ pub fn compiletest(build: &Build,
 
     if build.remote_tested(target) {
         cmd.arg("--remote-test-client")
-           .arg(build.tool(&Compiler::new(0, &build.config.build),
+           .arg(build.tool(&Compiler::new(0, &build.build),
                            "remote-test-client"));
     }
 
@@ -368,7 +366,7 @@ pub fn error_index(build: &Build, compiler: &Compiler) {
                              "error_index_generator")
                    .arg("markdown")
                    .arg(&output)
-                   .env("CFG_BUILD", &build.config.build));
+                   .env("CFG_BUILD", &build.build));
 
     markdown_test(build, compiler, &output);
 }
@@ -450,7 +448,7 @@ pub fn krate(build: &Build,
     cargo.arg("--manifest-path")
          .arg(build.src.join(path).join("Cargo.toml"))
          .arg("--features").arg(features);
-    if test_kind.subcommand() == "test" && build.flags.cmd.no_fail_fast() {
+    if test_kind.subcommand() == "test" && !build.fail_fast {
         cargo.arg("--no-fail-fast");
     }
 
@@ -520,16 +518,14 @@ fn krate_emscripten(build: &Build,
                     compiler: &Compiler,
                     target: &str,
                     mode: Mode) {
-    let mut tests = Vec::new();
     let out_dir = build.cargo_out(compiler, mode, target);
-    find_tests(&out_dir.join("deps"), target, &mut tests);
+    let tests = find_tests(&out_dir.join("deps"), target);
 
+    let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
     for test in tests {
-        let test_file_name = test.to_string_lossy().into_owned();
-        println!("running {}", test_file_name);
-        let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
+        println!("running {}", test.display());
         let mut cmd = Command::new(nodejs);
-        cmd.arg(&test_file_name);
+        cmd.arg(&test);
         if build.config.quiet_tests {
             cmd.arg("--quiet");
         }
@@ -541,11 +537,10 @@ fn krate_remote(build: &Build,
                 compiler: &Compiler,
                 target: &str,
                 mode: Mode) {
-    let mut tests = Vec::new();
     let out_dir = build.cargo_out(compiler, mode, target);
-    find_tests(&out_dir.join("deps"), target, &mut tests);
+    let tests = find_tests(&out_dir.join("deps"), target);
 
-    let tool = build.tool(&Compiler::new(0, &build.config.build),
+    let tool = build.tool(&Compiler::new(0, &build.build),
                           "remote-test-client");
     for test in tests {
         let mut cmd = Command::new(&tool);
@@ -559,9 +554,8 @@ fn krate_remote(build: &Build,
     }
 }
 
-fn find_tests(dir: &Path,
-              target: &str,
-              dst: &mut Vec<PathBuf>) {
+fn find_tests(dir: &Path, target: &str) -> Vec<PathBuf> {
+    let mut dst = Vec::new();
     for e in t!(dir.read_dir()).map(|e| t!(e)) {
         let file_type = t!(e.file_type());
         if !file_type.is_file() {
@@ -576,6 +570,7 @@ fn find_tests(dir: &Path,
             dst.push(e.path());
         }
     }
+    dst
 }
 
 pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
@@ -590,7 +585,7 @@ pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
                       .join(exe("remote-test-server", target));
 
     // Spawn the emulator and wait for it to come online
-    let tool = build.tool(&Compiler::new(0, &build.config.build),
+    let tool = build.tool(&Compiler::new(0, &build.build),
                           "remote-test-client");
     let mut cmd = Command::new(&tool);
     cmd.arg("spawn-emulator")
@@ -616,7 +611,7 @@ pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
 
 /// Run "distcheck", a 'make check' from a tarball
 pub fn distcheck(build: &Build) {
-    if build.config.build != "x86_64-unknown-linux-gnu" {
+    if build.build != "x86_64-unknown-linux-gnu" {
         return
     }
     if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") {
@@ -641,7 +636,7 @@ pub fn distcheck(build: &Build) {
                      .args(&build.config.configure_args)
                      .arg("--enable-vendor")
                      .current_dir(&dir));
-    build.run(Command::new(build_helper::make(&build.config.build))
+    build.run(Command::new(build_helper::make(&build.build))
                      .arg("check")
                      .current_dir(&dir));
 
@@ -659,7 +654,7 @@ pub fn distcheck(build: &Build) {
     build.run(&mut cmd);
 
     let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
-    build.run(Command::new(&build.cargo)
+    build.run(Command::new(&build.initial_cargo)
                      .arg("generate-lockfile")
                      .arg("--manifest-path")
                      .arg(&toml)
@@ -668,13 +663,13 @@ pub fn distcheck(build: &Build) {
 
 /// Test the build system itself
 pub fn bootstrap(build: &Build) {
-    let mut cmd = Command::new(&build.cargo);
+    let mut cmd = Command::new(&build.initial_cargo);
     cmd.arg("test")
        .current_dir(build.src.join("src/bootstrap"))
        .env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
        .env("RUSTC_BOOTSTRAP", "1")
-       .env("RUSTC", &build.rustc);
-    if build.flags.cmd.no_fail_fast() {
+       .env("RUSTC", &build.initial_rustc);
+    if !build.fail_fast {
         cmd.arg("--no-fail-fast");
     }
     cmd.arg("--").args(&build.flags.cmd.test_args());
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index b2bd792e93ba6..5a3106c7d5e64 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -50,7 +50,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
     let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build");
     let mut features = build.std_features();
 
-    if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") {
+    if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
 
@@ -158,7 +158,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
         return
     }
 
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
     let compiler_path = build.compiler_path(&compiler);
     let src_dir = &build.src.join("src/rtstartup");
     let dst_dir = &build.native_dir(target).join("rtstartup");
@@ -199,7 +199,7 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) {
     let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
     build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
     let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
-    if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") {
+    if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
     cargo.arg("--manifest-path")
@@ -247,7 +247,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
     cargo.env("CFG_RELEASE", build.rust_release())
          .env("CFG_RELEASE_CHANNEL", &build.config.channel)
          .env("CFG_VERSION", build.rust_version())
-         .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(PathBuf::new()));
+         .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
 
     if compiler.stage == 0 {
         cargo.env("CFG_LIBDIR_RELATIVE", "lib");
@@ -351,7 +351,7 @@ pub fn create_sysroot(build: &Build, compiler: &Compiler) {
 /// Prepare a new compiler from the artifacts in `stage`
 ///
 /// This will assemble a compiler in `build/$host/stage$stage`. The compiler
-/// must have been previously produced by the `stage - 1` build.config.build
+/// must have been previously produced by the `stage - 1` build.build
 /// compiler.
 pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     // nothing to do in stage0
@@ -365,7 +365,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     let target_compiler = Compiler::new(stage, host);
 
     // The compiler that compiled the compiler we're assembling
-    let build_compiler = Compiler::new(stage - 1, &build.config.build);
+    let build_compiler = Compiler::new(stage - 1, &build.build);
 
     // Link in all dylibs to the libdir
     let sysroot = build.sysroot(&target_compiler);
@@ -385,7 +385,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     let rustc = out_dir.join(exe("rustc", host));
     let bindir = sysroot.join("bin");
     t!(fs::create_dir_all(&bindir));
-    let compiler = build.compiler_path(&Compiler::new(stage, host));
+    let compiler = build.compiler_path(&target_compiler);
     let _ = fs::remove_file(&compiler);
     copy(&rustc, &compiler);
 
@@ -407,6 +407,8 @@ fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
     t!(fs::create_dir_all(&sysroot_dst));
     let mut contents = Vec::new();
     t!(t!(File::open(stamp)).read_to_end(&mut contents));
+    // This is the method we use for extracting paths from the stamp file passed to us. See
+    // run_cargo for more information (in this file).
     for part in contents.split(|b| *b == 0) {
         if part.is_empty() {
             continue
@@ -421,7 +423,7 @@ fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
 /// This will build the specified tool with the specified `host` compiler in
 /// `stage` into the normal cargo output directory.
 pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) {
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
 
     let stamp = match mode {
         Mode::Libstd => libstd_stamp(build, &compiler, target),
@@ -441,7 +443,7 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) {
     let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
     println!("Building stage{} tool {} ({})", stage, tool, target);
 
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
 
     let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build");
     let dir = build.src.join("src/tools").join(tool);
@@ -557,23 +559,24 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) {
             // If this was an output file in the "host dir" we don't actually
             // worry about it, it's not relevant for us.
             if filename.starts_with(&host_root_dir) {
-                continue
+                continue;
+            }
 
             // If this was output in the `deps` dir then this is a precise file
             // name (hash included) so we start tracking it.
-            } else if filename.starts_with(&target_deps_dir) {
+            if filename.starts_with(&target_deps_dir) {
                 deps.push(filename.to_path_buf());
+                continue;
+            }
 
             // Otherwise this was a "top level artifact" which right now doesn't
             // have a hash in the name, but there's a version of this file in
             // the `deps` folder which *does* have a hash in the name. That's
             // the one we'll want to we'll probe for it later.
-            } else {
-                toplevel.push((filename.file_stem().unwrap()
-                                       .to_str().unwrap().to_string(),
-                               filename.extension().unwrap().to_owned()
-                                       .to_str().unwrap().to_string()));
-            }
+            toplevel.push((filename.file_stem().unwrap()
+                                    .to_str().unwrap().to_string(),
+                            filename.extension().unwrap().to_owned()
+                                    .to_str().unwrap().to_string()));
         }
     }
 
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 3ada846e38236..34628852ab377 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -81,8 +81,6 @@ pub struct Config {
     pub build: String,
     pub host: Vec<String>,
     pub target: Vec<String>,
-    pub rustc: Option<PathBuf>,
-    pub cargo: Option<PathBuf>,
     pub local_rebuild: bool,
 
     // dist misc
@@ -114,11 +112,18 @@ pub struct Config {
     pub python: Option<PathBuf>,
     pub configure_args: Vec<String>,
     pub openssl_static: bool,
+
+
+    // These are either the stage0 downloaded binaries or the locally installed ones.
+    pub initial_cargo: PathBuf,
+    pub initial_rustc: PathBuf,
+
 }
 
 /// Per-target configuration stored in the global configuration structure.
 #[derive(Default)]
 pub struct Target {
+    /// Some(path to llvm-config) if using an external LLVM.
     pub llvm_config: Option<PathBuf>,
     pub jemalloc: Option<PathBuf>,
     pub cc: Option<PathBuf>,
@@ -307,8 +312,6 @@ impl Config {
                 config.target.push(target.clone());
             }
         }
-        config.rustc = build.rustc.map(PathBuf::from);
-        config.cargo = build.cargo.map(PathBuf::from);
         config.nodejs = build.nodejs.map(PathBuf::from);
         config.gdb = build.gdb.map(PathBuf::from);
         config.python = build.python.map(PathBuf::from);
@@ -410,13 +413,25 @@ impl Config {
             set(&mut config.rust_dist_src, t.src_tarball);
         }
 
+        let cwd = t!(env::current_dir());
+        let out = cwd.join("build");
+
+        let stage0_root = out.join(&config.build).join("stage0/bin");
+        config.initial_rustc = match build.rustc {
+            Some(s) => PathBuf::from(s),
+            None => stage0_root.join(exe("rustc", &config.build)),
+        };
+        config.initial_cargo = match build.cargo {
+            Some(s) => PathBuf::from(s),
+            None => stage0_root.join(exe("cargo", &config.build)),
+        };
 
         // compat with `./configure` while we're still using that
         if fs::metadata("config.mk").is_ok() {
             config.update_with_config_mk();
         }
 
-        return config
+        config
     }
 
     /// "Temporary" routine to parse `config.mk` into this configuration.
@@ -609,8 +624,8 @@ impl Config {
                 }
                 "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
                     let path = parse_configure_path(value);
-                    self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
-                    self.cargo = Some(push_exe_path(path, &["bin", "cargo"]));
+                    self.initial_rustc = push_exe_path(path.clone(), &["bin", "rustc"]);
+                    self.initial_cargo = push_exe_path(path, &["bin", "cargo"]);
                 }
                 "CFG_PYTHON" if value.len() > 0 => {
                     let path = parse_configure_path(value);
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 753bd1df0d83f..637bdbe998496 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -50,7 +50,7 @@ pub fn tmpdir(build: &Build) -> PathBuf {
 }
 
 fn rust_installer(build: &Build) -> Command {
-    build.tool_cmd(&Compiler::new(0, &build.config.build), "rust-installer")
+    build.tool_cmd(&Compiler::new(0, &build.build), "rust-installer")
 }
 
 /// Builds the `rust-docs` installer component.
@@ -89,7 +89,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
 
     // As part of this step, *also* copy the docs directory to a directory which
     // buildbot typically uploads.
-    if host == build.config.build {
+    if host == build.build {
         let dst = distdir(build).join("doc").join(build.rust_package_vers());
         t!(fs::create_dir_all(&dst));
         cp_r(&src, &dst);
@@ -97,7 +97,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
 }
 
 fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
-    let mut found = Vec::new();
+    let mut found = Vec::with_capacity(files.len());
 
     for file in files {
         let file_path =
@@ -119,17 +119,9 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
     //Ask gcc where it keeps its stuff
     let mut cmd = Command::new(build.cc(target_triple));
     cmd.arg("-print-search-dirs");
-    build.run_quiet(&mut cmd);
-    let gcc_out =
-        String::from_utf8(
-                cmd
-                .output()
-                .expect("failed to execute gcc")
-                .stdout).expect("gcc.exe output was not utf8");
-
-    let mut bin_path: Vec<_> =
-        env::split_paths(&env::var_os("PATH").unwrap_or_default())
-        .collect();
+    let gcc_out = output(&mut cmd);
+
+    let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
     let mut lib_path = Vec::new();
 
     for line in gcc_out.lines() {
@@ -140,7 +132,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
             line[(idx + 1)..]
                 .trim_left_matches(trim_chars)
                 .split(';')
-                .map(|s| PathBuf::from(s));
+                .map(PathBuf::from);
 
         if key == "programs" {
             bin_path.extend(value);
@@ -149,7 +141,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
         }
     }
 
-    let target_tools = vec!["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"];
+    let target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"];
     let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"];
     if target_triple.starts_with("i686-") {
         rustc_dlls.push("libgcc_s_dw2-1.dll");
@@ -157,7 +149,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
         rustc_dlls.push("libgcc_s_seh-1.dll");
     }
 
-    let target_libs = vec![ //MinGW libs
+    let target_libs = [ //MinGW libs
         "libgcc.a",
         "libgcc_eh.a",
         "libgcc_s.a",
@@ -203,7 +195,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
     let target_libs = find_files(&target_libs, &lib_path);
 
     fn copy_to_folder(src: &Path, dest_folder: &Path) {
-        let file_name = src.file_name().unwrap().to_os_string();
+        let file_name = src.file_name().unwrap();
         let dest = dest_folder.join(file_name);
         copy(src, &dest);
     }
@@ -234,8 +226,6 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build:
 ///
 /// This contains all the bits and pieces to run the MinGW Windows targets
 /// without any extra installed software (e.g. we bundle gcc, libraries, etc).
-/// Currently just shells out to a python script, but that should be rewritten
-/// in Rust.
 pub fn mingw(build: &Build, host: &str) {
     println!("Dist mingw ({})", host);
     let name = pkgname(build, "rust-mingw");
@@ -366,9 +356,9 @@ pub fn rustc(build: &Build, stage: u32, host: &str) {
 pub fn debugger_scripts(build: &Build,
                         sysroot: &Path,
                         host: &str) {
+    let dst = sysroot.join("lib/rustlib/etc");
+    t!(fs::create_dir_all(&dst));
     let cp_debugger_script = |file: &str| {
-        let dst = sysroot.join("lib/rustlib/etc");
-        t!(fs::create_dir_all(&dst));
         install(&build.src.join("src/etc/").join(file), &dst, 0o644);
     };
     if host.contains("windows-msvc") {
@@ -404,7 +394,7 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) {
 
     // The only true set of target libraries came from the build triple, so
     // let's reduce redundant work by only producing archives from that host.
-    if compiler.host != build.config.build {
+    if compiler.host != build.build {
         println!("\tskipping, not a build host");
         return
     }
@@ -450,7 +440,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
     assert!(build.config.extended);
     println!("Dist analysis");
 
-    if compiler.host != build.config.build {
+    if compiler.host != build.build {
         println!("\tskipping, not a build host");
         return;
     }
@@ -498,12 +488,11 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di
         if spath.ends_with("~") || spath.ends_with(".pyc") {
             return false
         }
-        if spath.contains("llvm/test") || spath.contains("llvm\\test") {
-            if spath.ends_with(".ll") ||
-               spath.ends_with(".td") ||
-               spath.ends_with(".s") {
-                return false
-            }
+        if (spath.contains("llvm/test") || spath.contains("llvm\\test")) &&
+            (spath.ends_with(".ll") ||
+             spath.ends_with(".td") ||
+             spath.ends_with(".s")) {
+            return false
         }
 
         let full_path = Path::new(dir).join(path);
@@ -564,10 +553,10 @@ pub fn rust_src(build: &Build) {
         "src/libstd",
         "src/libstd_unicode",
         "src/libunwind",
+        "src/rustc/compiler_builtins_shim",
         "src/rustc/libc_shim",
         "src/libtest",
         "src/libterm",
-        "src/compiler-rt",
         "src/jemalloc",
         "src/libprofiler_builtins",
     ];
@@ -595,7 +584,7 @@ pub fn rust_src(build: &Build) {
     t!(fs::remove_dir_all(&image));
 }
 
-const CARGO_VENDOR_VERSION: &'static str = "0.1.4";
+const CARGO_VENDOR_VERSION: &str = "0.1.4";
 
 /// Creates the plain source tarball
 pub fn plain_source_tarball(build: &Build) {
@@ -634,26 +623,26 @@ pub fn plain_source_tarball(build: &Build) {
     write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
 
     // If we're building from git sources, we need to vendor a complete distribution.
-    if build.src_is_git {
+    if build.rust_info.is_git() {
         // Get cargo-vendor installed, if it isn't already.
         let mut has_cargo_vendor = false;
-        let mut cmd = Command::new(&build.cargo);
+        let mut cmd = Command::new(&build.initial_cargo);
         for line in output(cmd.arg("install").arg("--list")).lines() {
             has_cargo_vendor |= line.starts_with("cargo-vendor ");
         }
         if !has_cargo_vendor {
-            let mut cmd = Command::new(&build.cargo);
+            let mut cmd = Command::new(&build.initial_cargo);
             cmd.arg("install")
                .arg("--force")
                .arg("--debug")
                .arg("--vers").arg(CARGO_VENDOR_VERSION)
                .arg("cargo-vendor")
-               .env("RUSTC", &build.rustc);
+               .env("RUSTC", &build.initial_rustc);
             build.run(&mut cmd);
         }
 
         // Vendor all Cargo dependencies
-        let mut cmd = Command::new(&build.cargo);
+        let mut cmd = Command::new(&build.initial_cargo);
         cmd.arg("vendor")
            .current_dir(&plain_dst_src.join("src"));
         build.run(&mut cmd);
@@ -716,7 +705,7 @@ fn write_file(path: &Path, data: &[u8]) {
 
 pub fn cargo(build: &Build, stage: u32, target: &str) {
     println!("Dist cargo stage{} ({})", stage, target);
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
 
     let src = build.src.join("src/tools/cargo");
     let etc = src.join("src/etc");
@@ -777,7 +766,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) {
 pub fn rls(build: &Build, stage: u32, target: &str) {
     assert!(build.config.extended);
     println!("Dist RLS stage{} ({})", stage, target);
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
 
     let src = build.src.join("src/tools/rls");
     let release_num = build.release_num("rls");
@@ -1209,7 +1198,7 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) {
 }
 
 pub fn hash_and_sign(build: &Build) {
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
     let mut cmd = build.tool_cmd(&compiler, "build-manifest");
     let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
         panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 30f631ca2df64..7dbc3e5553957 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -45,7 +45,7 @@ pub fn rustbook_src(build: &Build, target: &str, name: &str, src: &Path) {
     t!(fs::create_dir_all(&out));
 
     let out = out.join(name);
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
     let src = src.join(name);
     let index = out.join("index.html");
     let rustbook = build.tool(&compiler, "rustbook");
@@ -95,7 +95,7 @@ pub fn book(build: &Build, target: &str, name: &str) {
 fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) {
     let out = build.doc_out(target);
 
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
 
     let path = build.src.join("src/doc").join(markdown);
 
@@ -150,7 +150,7 @@ pub fn standalone(build: &Build, target: &str) {
     let out = build.doc_out(target);
     t!(fs::create_dir_all(&out));
 
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
 
     let favicon = build.src.join("src/doc/favicon.inc");
     let footer = build.src.join("src/doc/footer.inc");
@@ -217,7 +217,7 @@ pub fn std(build: &Build, stage: u32, target: &str) {
     println!("Documenting stage{} std ({})", stage, target);
     let out = build.doc_out(target);
     t!(fs::create_dir_all(&out));
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
     let compiler = if build.force_use_stage1(&compiler, target) {
         Compiler::new(1, compiler.host)
     } else {
@@ -276,7 +276,7 @@ pub fn test(build: &Build, stage: u32, target: &str) {
     println!("Documenting stage{} test ({})", stage, target);
     let out = build.doc_out(target);
     t!(fs::create_dir_all(&out));
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
     let compiler = if build.force_use_stage1(&compiler, target) {
         Compiler::new(1, compiler.host)
     } else {
@@ -306,7 +306,7 @@ pub fn rustc(build: &Build, stage: u32, target: &str) {
     println!("Documenting stage{} compiler ({})", stage, target);
     let out = build.doc_out(target);
     t!(fs::create_dir_all(&out));
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(stage, &build.build);
     let compiler = if build.force_use_stage1(&compiler, target) {
         Compiler::new(1, compiler.host)
     } else {
@@ -351,13 +351,13 @@ pub fn error_index(build: &Build, target: &str) {
     println!("Documenting error index ({})", target);
     let out = build.doc_out(target);
     t!(fs::create_dir_all(&out));
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
     let mut index = build.tool_cmd(&compiler, "error_index_generator");
     index.arg("html");
     index.arg(out.join("error-index.html"));
 
     // FIXME: shouldn't have to pass this env var
-    index.env("CFG_BUILD", &build.config.build);
+    index.env("CFG_BUILD", &build.build);
 
     build.run(&mut index);
 }
@@ -367,7 +367,7 @@ pub fn unstable_book_gen(build: &Build, target: &str) {
     let out = build.md_doc_out(target).join("unstable-book");
     t!(fs::create_dir_all(&out));
     t!(fs::remove_dir_all(&out));
-    let compiler = Compiler::new(0, &build.config.build);
+    let compiler = Compiler::new(0, &build.build);
     let mut cmd = build.tool_cmd(&compiler, "unstable-book-gen");
     cmd.arg(build.src.join("src"));
     cmd.arg(out);
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index dc9dac7362788..5804df34e8b38 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -35,22 +35,12 @@ pub struct Flags {
     pub host: Vec<String>,
     pub target: Vec<String>,
     pub config: Option<PathBuf>,
-    pub src: Option<PathBuf>,
+    pub src: PathBuf,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
     pub incremental: bool,
 }
 
-impl Flags {
-    pub fn verbose(&self) -> bool {
-        self.verbose > 0
-    }
-
-    pub fn very_verbose(&self) -> bool {
-        self.verbose > 1
-    }
-}
-
 pub enum Subcommand {
     Build {
         paths: Vec<PathBuf>,
@@ -61,7 +51,7 @@ pub enum Subcommand {
     Test {
         paths: Vec<PathBuf>,
         test_args: Vec<String>,
-        no_fail_fast: bool,
+        fail_fast: bool,
     },
     Bench {
         paths: Vec<PathBuf>,
@@ -122,16 +112,15 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
         // the subcommand. Therefore we must manually identify the subcommand first, so that we can
         // complete the definition of the options.  Then we can use the getopt::Matches object from
         // there on out.
-        let mut possible_subcommands = args.iter().collect::<Vec<_>>();
-        possible_subcommands.retain(|&s|
-                                           (s == "build")
-                                        || (s == "test")
-                                        || (s == "bench")
-                                        || (s == "doc")
-                                        || (s == "clean")
-                                        || (s == "dist")
-                                        || (s == "install"));
-        let subcommand = match possible_subcommands.first() {
+        let subcommand = args.iter().find(|&s|
+            (s == "build")
+            || (s == "test")
+            || (s == "bench")
+            || (s == "doc")
+            || (s == "clean")
+            || (s == "dist")
+            || (s == "install"));
+        let subcommand = match subcommand {
             Some(s) => s,
             None => {
                 // No subcommand -- show the general usage and subcommand help
@@ -164,7 +153,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
         let mut pass_sanity_check = true;
         match matches.free.get(0) {
             Some(check_subcommand) => {
-                if &check_subcommand != subcommand {
+                if check_subcommand != subcommand {
                     pass_sanity_check = false;
                 }
             },
@@ -279,7 +268,7 @@ Arguments:
                 Subcommand::Test {
                     paths: paths,
                     test_args: matches.opt_strs("test-args"),
-                    no_fail_fast: matches.opt_present("no-fail-fast"),
+                    fail_fast: !matches.opt_present("no-fail-fast"),
                 }
             }
             "bench" => {
@@ -316,12 +305,15 @@ Arguments:
 
         let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());
 
-        if matches.opt_present("incremental") {
-            if stage.is_none() {
-                stage = Some(1);
-            }
+        if matches.opt_present("incremental") && stage.is_none() {
+            stage = Some(1);
         }
 
+        let cwd = t!(env::current_dir());
+        let src = matches.opt_str("src").map(PathBuf::from)
+            .or_else(|| env::var_os("SRC").map(PathBuf::from))
+            .unwrap_or(cwd);
+
         Flags {
             verbose: matches.opt_count("verbose"),
             stage: stage,
@@ -333,7 +325,7 @@ Arguments:
             host: split(matches.opt_strs("host")),
             target: split(matches.opt_strs("target")),
             config: cfg_file,
-            src: matches.opt_str("src").map(PathBuf::from),
+            src: src,
             jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
             cmd: cmd,
             incremental: matches.opt_present("incremental"),
@@ -352,9 +344,9 @@ impl Subcommand {
         }
     }
 
-    pub fn no_fail_fast(&self) -> bool {
+    pub fn fail_fast(&self) -> bool {
         match *self {
-            Subcommand::Test { no_fail_fast, .. } => no_fail_fast,
+            Subcommand::Test { fail_fast, .. } => fail_fast,
             _ => false,
         }
     }
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 21e21628dc947..8e2ef527b1658 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -146,5 +146,5 @@ fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
             _ => {}
         }
     }
-    return ret
+    ret
 }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 86180077b82f8..5a3785b1ed634 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -161,25 +161,35 @@ pub struct Build {
     flags: Flags,
 
     // Derived properties from the above two configurations
-    cargo: PathBuf,
-    rustc: PathBuf,
     src: PathBuf,
     out: PathBuf,
     rust_info: channel::GitInfo,
     cargo_info: channel::GitInfo,
     rls_info: channel::GitInfo,
     local_rebuild: bool,
+    fail_fast: bool,
+    verbosity: usize,
+
+    // Targets for which to build.
+    build: String,
+    hosts: Vec<String>,
+    targets: Vec<String>,
+
+    // Stage 0 (downloaded) compiler and cargo or their local rust equivalents.
+    initial_rustc: PathBuf,
+    initial_cargo: PathBuf,
 
     // Probed tools at runtime
     lldb_version: Option<String>,
     lldb_python_dir: Option<String>,
 
     // Runtime state filled in later on
+    // target -> (cc, ar)
     cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
+    // host -> (cc, ar)
     cxx: HashMap<String, gcc::Tool>,
     crates: HashMap<String, Crate>,
     is_sudo: bool,
-    src_is_git: bool,
     ci_env: CiEnv,
     delayed_failures: Cell<usize>,
 }
@@ -202,20 +212,16 @@ struct Crate {
 /// build system, with each mod generating output in a different directory.
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub enum Mode {
-    /// This cargo is going to build the standard library, placing output in the
-    /// "stageN-std" directory.
+    /// Build the standard library, placing output in the "stageN-std" directory.
     Libstd,
 
-    /// This cargo is going to build libtest, placing output in the
-    /// "stageN-test" directory.
+    /// Build libtest, placing output in the "stageN-test" directory.
     Libtest,
 
-    /// This cargo is going to build librustc and compiler libraries, placing
-    /// output in the "stageN-rustc" directory.
+    /// Build librustc and compiler libraries, placing output in the "stageN-rustc" directory.
     Librustc,
 
-    /// This cargo is going to build some tool, placing output in the
-    /// "stageN-tools" directory.
+    /// Build some tool, placing output in the "stageN-tools" directory.
     Tool,
 }
 
@@ -226,22 +232,9 @@ impl Build {
     /// By default all build output will be placed in the current directory.
     pub fn new(flags: Flags, config: Config) -> Build {
         let cwd = t!(env::current_dir());
-        let src = flags.src.clone().or_else(|| {
-            env::var_os("SRC").map(|x| x.into())
-        }).unwrap_or(cwd.clone());
+        let src = flags.src.clone();
         let out = cwd.join("build");
 
-        let stage0_root = out.join(&config.build).join("stage0/bin");
-        let rustc = match config.rustc {
-            Some(ref s) => PathBuf::from(s),
-            None => stage0_root.join(exe("rustc", &config.build)),
-        };
-        let cargo = match config.cargo {
-            Some(ref s) => PathBuf::from(s),
-            None => stage0_root.join(exe("cargo", &config.build)),
-        };
-        let local_rebuild = config.local_rebuild;
-
         let is_sudo = match env::var_os("SUDO_USER") {
             Some(sudo_user) => {
                 match env::var_os("USER") {
@@ -254,32 +247,64 @@ impl Build {
         let rust_info = channel::GitInfo::new(&src);
         let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo"));
         let rls_info = channel::GitInfo::new(&src.join("src/tools/rls"));
-        let src_is_git = src.join(".git").exists();
+
+        let hosts = if !flags.host.is_empty() {
+            for host in flags.host.iter() {
+                if !config.host.contains(host) {
+                    panic!("specified host `{}` is not in configuration", host);
+                }
+            }
+            flags.host.clone()
+        } else {
+            config.host.clone()
+        };
+        let targets = if !flags.target.is_empty() {
+            for target in flags.target.iter() {
+                if !config.target.contains(target) {
+                    panic!("specified target `{}` is not in configuration", target);
+                }
+            }
+            flags.target.clone()
+        } else {
+            config.target.clone()
+        };
 
         Build {
+            initial_rustc: config.initial_rustc.clone(),
+            initial_cargo: config.initial_cargo.clone(),
+            local_rebuild: config.local_rebuild,
+            fail_fast: flags.cmd.fail_fast(),
+            verbosity: cmp::max(flags.verbose, config.verbose),
+
+            build: config.host[0].clone(),
+            hosts: hosts,
+            targets: targets,
+
             flags: flags,
             config: config,
-            cargo: cargo,
-            rustc: rustc,
             src: src,
             out: out,
 
             rust_info: rust_info,
             cargo_info: cargo_info,
             rls_info: rls_info,
-            local_rebuild: local_rebuild,
             cc: HashMap::new(),
             cxx: HashMap::new(),
             crates: HashMap::new(),
             lldb_version: None,
             lldb_python_dir: None,
             is_sudo: is_sudo,
-            src_is_git: src_is_git,
             ci_env: CiEnv::current(),
             delayed_failures: Cell::new(0),
         }
     }
 
+    fn build_slice(&self) -> &[String] {
+        unsafe {
+            std::slice::from_raw_parts(&self.build, 1)
+        }
+    }
+
     /// Executes the entire build, as configured by the flags and configuration.
     pub fn build(&mut self) {
         unsafe {
@@ -296,7 +321,7 @@ impl Build {
         sanity::check(self);
         // If local-rust is the same major.minor as the current version, then force a local-rebuild
         let local_version_verbose = output(
-            Command::new(&self.rustc).arg("--version").arg("--verbose"));
+            Command::new(&self.initial_rustc).arg("--version").arg("--verbose"));
         let local_release = local_version_verbose
             .lines().filter(|x| x.starts_with("release:"))
             .next().unwrap().trim_left_matches("release:").trim();
@@ -338,7 +363,7 @@ impl Build {
              mode: Mode,
              target: &str,
              cmd: &str) -> Command {
-        let mut cargo = Command::new(&self.cargo);
+        let mut cargo = Command::new(&self.initial_cargo);
         let out_dir = self.stage_out(compiler, mode);
         cargo.env("CARGO_TARGET_DIR", out_dir)
              .arg(cmd)
@@ -422,7 +447,7 @@ impl Build {
         // library up and running, so we can use the normal compiler to compile
         // build scripts in that situation.
         if mode == Mode::Libstd {
-            cargo.env("RUSTC_SNAPSHOT", &self.rustc)
+            cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
                  .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
         } else {
             cargo.env("RUSTC_SNAPSHOT", self.compiler_path(compiler))
@@ -441,8 +466,7 @@ impl Build {
             cargo.env("RUSTC_ON_FAIL", on_fail);
         }
 
-        let verbose = cmp::max(self.config.verbose, self.flags.verbose);
-        cargo.env("RUSTC_VERBOSE", format!("{}", verbose));
+        cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
 
         // Specify some various options for build scripts used throughout
         // the build.
@@ -458,7 +482,9 @@ impl Build {
             }
         }
 
-        if self.config.extended && compiler.is_final_stage(self) {
+        if mode == Mode::Libstd &&
+           self.config.extended &&
+           compiler.is_final_stage(self) {
             cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
         }
 
@@ -480,7 +506,7 @@ impl Build {
         // FIXME: should update code to not require this env var
         cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
 
-        if self.config.verbose() || self.flags.verbose() {
+        if self.is_verbose() {
             cargo.arg("-v");
         }
         // FIXME: cargo bench does not accept `--release`
@@ -496,13 +522,13 @@ impl Build {
 
         self.ci_env.force_coloring_in_ci(&mut cargo);
 
-        return cargo
+        cargo
     }
 
     /// Get a path to the compiler specified.
     fn compiler_path(&self, compiler: &Compiler) -> PathBuf {
         if compiler.is_snapshot(self) {
-            self.rustc.clone()
+            self.initial_rustc.clone()
         } else {
             self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
         }
@@ -519,7 +545,7 @@ impl Build {
         let mut rustdoc = self.compiler_path(compiler);
         rustdoc.pop();
         rustdoc.push(exe("rustdoc", compiler.host));
-        return rustdoc
+        rustdoc
     }
 
     /// Get a `Command` which is ready to run `tool` in `stage` built for
@@ -527,7 +553,7 @@ impl Build {
     fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
         let mut cmd = Command::new(self.tool(&compiler, tool));
         self.prepare_tool_cmd(compiler, &mut cmd);
-        return cmd
+        cmd
     }
 
     /// Prepares the `cmd` provided to be able to run the `compiler` provided.
@@ -578,7 +604,7 @@ impl Build {
         if self.config.profiler {
             features.push_str(" profiler");
         }
-        return features
+        features
     }
 
     /// Get the space-separated set of activated features for the compiler.
@@ -587,7 +613,7 @@ impl Build {
         if self.config.use_jemalloc {
             features.push_str(" jemalloc");
         }
-        return features
+        features
     }
 
     /// Component directory that Cargo will produce output into (e.g.
@@ -760,7 +786,7 @@ impl Build {
 
     /// Returns the libdir of the snapshot compiler.
     fn rustc_snapshot_libdir(&self) -> PathBuf {
-        self.rustc.parent().unwrap().parent().unwrap()
+        self.initial_rustc.parent().unwrap().parent().unwrap()
             .join(libdir(&self.config.build))
     }
 
@@ -792,9 +818,17 @@ impl Build {
         try_run_suppressed(cmd)
     }
 
+    pub fn is_verbose(&self) -> bool {
+        self.verbosity > 0
+    }
+
+    pub fn is_very_verbose(&self) -> bool {
+        self.verbosity > 1
+    }
+
     /// Prints a message if this build is configured in verbose mode.
     fn verbose(&self, msg: &str) {
-        if self.flags.verbose() || self.config.verbose() {
+        if self.is_verbose() {
             println!("{}", msg);
         }
     }
@@ -802,7 +836,7 @@ impl Build {
     /// Returns the number of parallel jobs that have been configured for this
     /// build.
     fn jobs(&self) -> u32 {
-        self.flags.jobs.unwrap_or(num_cpus::get() as u32)
+        self.flags.jobs.unwrap_or_else(|| num_cpus::get() as u32)
     }
 
     /// Returns the path to the C compiler for the target specified.
@@ -834,7 +868,7 @@ impl Build {
         if target == "i686-pc-windows-gnu" {
             base.push("-fno-omit-frame-pointer".into());
         }
-        return base
+        base
     }
 
     /// Returns the path to the `ar` archive utility for the target specified.
@@ -866,7 +900,7 @@ impl Build {
             !target.contains("emscripten") {
             base.push(format!("-Clinker={}", self.cc(target).display()));
         }
-        return base
+        base
     }
 
     /// Returns the "musl root" for this `target`, if defined
@@ -1047,7 +1081,7 @@ impl<'a> Compiler<'a> {
 
     /// Returns whether this is a snapshot compiler for `build`'s configuration
     fn is_snapshot(&self, build: &Build) -> bool {
-        self.stage == 0 && self.host == build.config.build
+        self.stage == 0 && self.host == build.build
     }
 
     /// Returns if this compiler should be treated as a final stage one in the
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index 7b6b01655df58..9326bb7129afa 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -56,7 +56,7 @@ fn build_krate(build: &mut Build, krate: &str) {
     // of packages we're going to have to know what `-p` arguments to pass it
     // to know what crates to test. Here we run `cargo metadata` to learn about
     // the dependency graph and what `-p` arguments there are.
-    let mut cargo = Command::new(&build.cargo);
+    let mut cargo = Command::new(&build.initial_cargo);
     cargo.arg("metadata")
          .arg("--format-version").arg("1")
          .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index f150df6cdcdb0..20eec97d8e5aa 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -94,7 +94,7 @@ pub fn llvm(build: &Build, target: &str) {
     let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
 
     cfg.target(target)
-       .host(&build.config.build)
+       .host(&build.build)
        .out_dir(&out_dir)
        .profile(profile)
        .define("LLVM_ENABLE_ASSERTIONS", assertions)
@@ -129,11 +129,11 @@ pub fn llvm(build: &Build, target: &str) {
     }
 
     // http://llvm.org/docs/HowToCrossCompileLLVM.html
-    if target != build.config.build {
+    if target != build.build {
         // FIXME: if the llvm root for the build triple is overridden then we
         //        should use llvm-tblgen from there, also should verify that it
         //        actually exists most of the time in normal installs of LLVM.
-        let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
+        let host = build.llvm_out(&build.build).join("bin/llvm-tblgen");
         cfg.define("CMAKE_CROSSCOMPILING", "True")
            .define("LLVM_TABLEGEN", &host);
     }
@@ -243,7 +243,7 @@ pub fn test_helpers(build: &Build, target: &str) {
     cfg.cargo_metadata(false)
        .out_dir(&dst)
        .target(target)
-       .host(&build.config.build)
+       .host(&build.build)
        .opt_level(0)
        .debug(false)
        .file(build.src.join("src/rt/rust_test_helpers.c"))
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 46d047bb015e5..a9c1b023dd4f5 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -18,9 +18,9 @@
 //! In theory if we get past this phase it's a bug if a build fails, but in
 //! practice that's likely not true!
 
-use std::collections::HashSet;
+use std::collections::HashMap;
 use std::env;
-use std::ffi::{OsStr, OsString};
+use std::ffi::{OsString, OsStr};
 use std::fs;
 use std::process::Command;
 use std::path::PathBuf;
@@ -29,45 +29,59 @@ use build_helper::output;
 
 use Build;
 
+struct Finder {
+    cache: HashMap<OsString, Option<PathBuf>>,
+    path: OsString,
+}
+
+impl Finder {
+    fn new() -> Self {
+        Self {
+            cache: HashMap::new(),
+            path: env::var_os("PATH").unwrap_or_default()
+        }
+    }
+
+    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
+        let cmd: OsString = cmd.as_ref().into();
+        let path = self.path.clone();
+        self.cache.entry(cmd.clone()).or_insert_with(|| {
+            for path in env::split_paths(&path) {
+                let target = path.join(&cmd);
+                let mut cmd_alt = cmd.clone();
+                cmd_alt.push(".exe");
+                if target.is_file() || // some/path/git
+                target.with_extension("exe").exists() || // some/path/git.exe
+                target.join(&cmd_alt).exists() { // some/path/git/git.exe
+                    return Some(target);
+                }
+            }
+            None
+        }).clone()
+    }
+
+    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
+        self.maybe_have(&cmd).unwrap_or_else(|| {
+            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
+        })
+    }
+}
+
 pub fn check(build: &mut Build) {
-    let mut checked = HashSet::new();
-    let path = env::var_os("PATH").unwrap_or(OsString::new());
+    let path = env::var_os("PATH").unwrap_or_default();
     // On Windows, quotes are invalid characters for filename paths, and if
     // one is present as part of the PATH then that can lead to the system
     // being unable to identify the files properly. See
     // https://github.com/rust-lang/rust/issues/34959 for more details.
-    if cfg!(windows) {
-        if path.to_string_lossy().contains("\"") {
-            panic!("PATH contains invalid character '\"'");
-        }
+    if cfg!(windows) && path.to_string_lossy().contains("\"") {
+        panic!("PATH contains invalid character '\"'");
     }
-    let have_cmd = |cmd: &OsStr| {
-        for path in env::split_paths(&path) {
-            let target = path.join(cmd);
-            let mut cmd_alt = cmd.to_os_string();
-            cmd_alt.push(".exe");
-            if target.is_file() ||
-               target.with_extension("exe").exists() ||
-               target.join(cmd_alt).exists() {
-                return Some(target);
-            }
-        }
-        return None;
-    };
-
-    let mut need_cmd = |cmd: &OsStr| {
-        if !checked.insert(cmd.to_owned()) {
-            return
-        }
-        if have_cmd(cmd).is_none() {
-            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
-        }
-    };
 
+    let mut cmd_finder = Finder::new();
     // If we've got a git directory we're gona need git to update
     // submodules and learn about various other aspects.
-    if build.src_is_git {
-        need_cmd("git".as_ref());
+    if build.rust_info.is_git() {
+        cmd_finder.must_have("git");
     }
 
     // We need cmake, but only if we're actually building LLVM or sanitizers.
@@ -75,57 +89,32 @@ pub fn check(build: &mut Build) {
         .filter_map(|host| build.config.target_config.get(host))
         .any(|config| config.llvm_config.is_none());
     if building_llvm || build.config.sanitizers {
-        need_cmd("cmake".as_ref());
+        cmd_finder.must_have("cmake");
     }
 
     // Ninja is currently only used for LLVM itself.
-    if building_llvm && build.config.ninja {
-        // Some Linux distros rename `ninja` to `ninja-build`.
-        // CMake can work with either binary name.
-        if have_cmd("ninja-build".as_ref()).is_none() {
-            need_cmd("ninja".as_ref());
-        }
+    // Some Linux distros rename `ninja` to `ninja-build`.
+    // CMake can work with either binary name.
+    if building_llvm && build.config.ninja && cmd_finder.maybe_have("ninja-build").is_none() {
+        cmd_finder.must_have("ninja");
     }
 
-    if build.config.python.is_none() {
-        // set by bootstrap.py
-        if let Some(v) = env::var_os("BOOTSTRAP_PYTHON") {
-            build.config.python = Some(PathBuf::from(v));
-        }
-    }
-    if build.config.python.is_none() {
-        build.config.python = have_cmd("python2.7".as_ref());
-    }
-    if build.config.python.is_none() {
-        build.config.python = have_cmd("python2".as_ref());
-    }
-    if build.config.python.is_none() {
-        need_cmd("python".as_ref());
-        build.config.python = Some("python".into());
-    }
-    need_cmd(build.config.python.as_ref().unwrap().as_ref());
+    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
+        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
+        .or_else(|| cmd_finder.maybe_have("python2.7"))
+        .or_else(|| cmd_finder.maybe_have("python2"))
+        .or_else(|| Some(cmd_finder.must_have("python")));
 
+    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
+        .or_else(|| cmd_finder.maybe_have("node"))
+        .or_else(|| cmd_finder.maybe_have("nodejs"));
 
-    if let Some(ref s) = build.config.nodejs {
-        need_cmd(s.as_ref());
-    } else {
-        // Look for the nodejs command, needed for emscripten testing
-        if let Some(node) = have_cmd("node".as_ref()) {
-            build.config.nodejs = Some(node);
-        } else if let Some(node) = have_cmd("nodejs".as_ref()) {
-            build.config.nodejs = Some(node);
-        }
-    }
-
-    if let Some(ref gdb) = build.config.gdb {
-        need_cmd(gdb.as_ref());
-    } else {
-        build.config.gdb = have_cmd("gdb".as_ref());
-    }
+    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
+        .or_else(|| cmd_finder.maybe_have("gdb"));
 
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
-    for target in build.config.target.iter() {
+    for target in &build.config.target {
         // On emscripten we don't actually need the C compiler to just
         // build the target artifacts, only for testing. For the sake
         // of easier bot configuration, just skip detection.
@@ -133,33 +122,32 @@ pub fn check(build: &mut Build) {
             continue;
         }
 
-        need_cmd(build.cc(target).as_ref());
+        cmd_finder.must_have(build.cc(target));
         if let Some(ar) = build.ar(target) {
-            need_cmd(ar.as_ref());
+            cmd_finder.must_have(ar);
         }
     }
-    for host in build.config.host.iter() {
-        need_cmd(build.cxx(host).unwrap().as_ref());
-    }
 
-    // The msvc hosts don't use jemalloc, turn it off globally to
-    // avoid packaging the dummy liballoc_jemalloc on that platform.
     for host in build.config.host.iter() {
+        cmd_finder.must_have(build.cxx(host).unwrap());
+
+        // The msvc hosts don't use jemalloc, turn it off globally to
+        // avoid packaging the dummy liballoc_jemalloc on that platform.
         if host.contains("msvc") {
             build.config.use_jemalloc = false;
         }
     }
 
     // Externally configured LLVM requires FileCheck to exist
-    let filecheck = build.llvm_filecheck(&build.config.build);
+    let filecheck = build.llvm_filecheck(&build.build);
     if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
         panic!("FileCheck executable {:?} does not exist", filecheck);
     }
 
-    for target in build.config.target.iter() {
+    for target in &build.config.target {
         // Can't compile for iOS unless we're on macOS
         if target.contains("apple-ios") &&
-           !build.config.build.contains("apple-darwin") {
+           !build.build.contains("apple-darwin") {
             panic!("the iOS target is only supported on macOS");
         }
 
@@ -206,18 +194,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
         }
     }
 
-    for host in build.flags.host.iter() {
-        if !build.config.host.contains(host) {
-            panic!("specified host `{}` is not in the ./configure list", host);
-        }
-    }
-    for target in build.flags.target.iter() {
-        if !build.config.target.contains(target) {
-            panic!("specified target `{}` is not in the ./configure list",
-                   target);
-        }
-    }
-
     let run = |cmd: &mut Command| {
         cmd.output().map(|output| {
             String::from_utf8_lossy(&output.stdout)
@@ -231,6 +207,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
     }
 
     if let Some(ref s) = build.config.ccache {
-        need_cmd(s.as_ref());
+        cmd_finder.must_have(s);
     }
 }
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 5f0724c657757..c221d7076832f 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -104,10 +104,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.build("llvm", "src/llvm")
          .host(true)
          .dep(move |s| {
-             if s.target == build.config.build {
+             if s.target == build.build {
                  Step::noop()
              } else {
-                 s.target(&build.config.build)
+                 s.target(&build.build)
              }
          })
          .run(move |s| native::llvm(build, s.target));
@@ -124,7 +124,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                  Step::noop()
              } else {
                  s.name("librustc")
-                  .host(&build.config.build)
+                  .host(&build.build)
                   .stage(s.stage - 1)
              }
          })
@@ -148,7 +148,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                 }
             }
         }
-        return ret
+        ret
     };
 
     // ========================================================================
@@ -215,29 +215,29 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
         let mut rule = rules.build(&krate, "path/to/nowhere");
         rule.dep(move |s| {
                 if build.force_use_stage1(&s.compiler(), s.target) {
-                    s.host(&build.config.build).stage(1)
-                } else if s.host == build.config.build {
+                    s.host(&build.build).stage(1)
+                } else if s.host == build.build {
                     s.name(dep)
                 } else {
-                    s.host(&build.config.build)
+                    s.host(&build.build)
                 }
             })
             .run(move |s| {
                 if build.force_use_stage1(&s.compiler(), s.target) {
                     link(build,
-                         &s.stage(1).host(&build.config.build).compiler(),
+                         &s.stage(1).host(&build.build).compiler(),
                          &s.compiler(),
                          s.target)
-                } else if s.host == build.config.build {
+                } else if s.host == build.build {
                     link(build, &s.compiler(), &s.compiler(), s.target)
                 } else {
                     link(build,
-                         &s.host(&build.config.build).compiler(),
+                         &s.host(&build.build).compiler(),
                          &s.compiler(),
                          s.target)
                 }
             });
-            return rule
+            rule
     }
 
     // Similar to the `libstd`, `libtest`, and `librustc` rules above, except
@@ -269,7 +269,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     for (krate, path, _default) in krates("std") {
         rules.build(&krate.build_step, path)
              .dep(|s| s.name("startup-objects"))
-             .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
+             .dep(move |s| s.name("rustc").host(&build.build).target(s.host))
              .run(move |s| compile::std(build, s.target, &s.compiler()));
     }
     for (krate, path, _default) in krates("test") {
@@ -280,7 +280,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     for (krate, path, _default) in krates("rustc-main") {
         rules.build(&krate.build_step, path)
              .dep(|s| s.name("libtest-link"))
-             .dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
+             .dep(move |s| s.name("llvm").host(&build.build).stage(0))
              .dep(|s| s.name("may-run-build-script"))
              .run(move |s| compile::rustc(build, s.target, &s.compiler()));
     }
@@ -291,8 +291,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.build("may-run-build-script", "path/to/nowhere")
          .dep(move |s| {
              s.name("libstd-link")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
          });
     rules.build("startup-objects", "src/rtstartup")
          .dep(|s| s.name("create-sysroot").target(s.host))
@@ -332,7 +332,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
               "incremental");
     }
 
-    if build.config.build.contains("msvc") {
+    if build.build.contains("msvc") {
         // nothing to do for debuginfo tests
     } else {
         rules.test("check-debuginfo-lldb", "src/test/debuginfo-lldb")
@@ -352,7 +352,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                                          "debuginfo-gdb", "debuginfo"));
         let mut rule = rules.test("check-debuginfo", "src/test/debuginfo");
         rule.default(true);
-        if build.config.build.contains("apple") {
+        if build.build.contains("apple") {
             rule.dep(|s| s.name("check-debuginfo-lldb"));
         } else {
             rule.dep(|s| s.name("check-debuginfo-gdb"));
@@ -594,8 +594,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
              // Cargo depends on procedural macros, which requires a full host
              // compiler to be available, so we need to depend on that.
              s.name("librustc-link")
-              .target(&build.config.build)
-              .host(&build.config.build)
+              .target(&build.build)
+              .host(&build.build)
          })
          .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
     rules.build("tool-rls", "src/tools/rls")
@@ -606,8 +606,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
          .dep(move |s| {
              // rls, like cargo, uses procedural macros
              s.name("librustc-link")
-              .target(&build.config.build)
-              .host(&build.config.build)
+              .target(&build.build)
+              .host(&build.build)
          })
          .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
 
@@ -635,8 +635,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.doc("doc-book", "src/doc/book")
          .dep(move |s| {
              s.name("tool-rustbook")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
               .stage(0)
          })
          .default(build.config.docs)
@@ -644,8 +644,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.doc("doc-nomicon", "src/doc/nomicon")
          .dep(move |s| {
              s.name("tool-rustbook")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
               .stage(0)
          })
          .default(build.config.docs)
@@ -653,8 +653,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.doc("doc-reference", "src/doc/reference")
          .dep(move |s| {
              s.name("tool-rustbook")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
               .stage(0)
          })
          .default(build.config.docs)
@@ -662,8 +662,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.doc("doc-unstable-book", "src/doc/unstable-book")
          .dep(move |s| {
              s.name("tool-rustbook")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
               .stage(0)
          })
          .dep(move |s| s.name("doc-unstable-book-gen"))
@@ -675,14 +675,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.doc("doc-standalone", "src/doc")
          .dep(move |s| {
              s.name("rustc")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
               .stage(0)
          })
          .default(build.config.docs)
          .run(move |s| doc::standalone(build, s.target));
     rules.doc("doc-error-index", "src/tools/error_index_generator")
-         .dep(move |s| s.name("tool-error-index").target(&build.config.build).stage(0))
+         .dep(move |s| s.name("tool-error-index").target(&build.build).stage(0))
          .dep(move |s| s.name("librustc-link"))
          .default(build.config.docs)
          .host(true)
@@ -690,8 +690,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.doc("doc-unstable-book-gen", "src/tools/unstable-book-gen")
          .dep(move |s| {
              s.name("tool-unstable-book-gen")
-              .host(&build.config.build)
-              .target(&build.config.build)
+              .host(&build.build)
+              .target(&build.build)
               .stage(0)
          })
          .dep(move |s| s.name("libstd-link"))
@@ -725,7 +725,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     // ========================================================================
     // Distribution targets
     rules.dist("dist-rustc", "src/librustc")
-         .dep(move |s| s.name("rustc").host(&build.config.build))
+         .dep(move |s| s.name("rustc").host(&build.build))
          .host(true)
          .only_host_build(true)
          .default(true)
@@ -811,7 +811,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
          .host(true)
          .only_build(true)
          .only_host_build(true)
-         .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0))
+         .dep(move |s| s.name("tool-build-manifest").target(&build.build).stage(0))
          .run(move |_| dist::hash_and_sign(build));
 
     rules.install("install-docs", "src/doc")
@@ -861,8 +861,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     /// Helper to depend on a stage0 build-only rust-installer tool.
     fn tool_rust_installer<'a>(build: &'a Build, step: &Step<'a>) -> Step<'a> {
         step.name("tool-rust-installer")
-            .host(&build.config.build)
-            .target(&build.config.build)
+            .host(&build.build)
+            .target(&build.build)
             .stage(0)
     }
 }
@@ -1058,8 +1058,8 @@ impl<'a> Rules<'a> {
             build: build,
             sbuild: Step {
                 stage: build.flags.stage.unwrap_or(2),
-                target: &build.config.build,
-                host: &build.config.build,
+                target: &build.build,
+                host: &build.build,
                 name: "",
             },
             rules: BTreeMap::new(),
@@ -1218,16 +1218,9 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
 
         rules.into_iter().flat_map(|(rule, _)| {
             let hosts = if rule.only_host_build || rule.only_build {
-                &self.build.config.host[..1]
-            } else if self.build.flags.host.len() > 0 {
-                &self.build.flags.host
+                self.build.build_slice()
             } else {
-                &self.build.config.host
-            };
-            let targets = if self.build.flags.target.len() > 0 {
-                &self.build.flags.target
-            } else {
-                &self.build.config.target
+                &self.build.hosts
             };
             // Determine the actual targets participating in this rule.
             // NOTE: We should keep the full projection from build triple to
@@ -1236,19 +1229,18 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
             // the original non-shadowed hosts array is used below.
             let arr = if rule.host {
                 // If --target was specified but --host wasn't specified,
-                // don't run any host-only tests. Also, respect any `--host`
-                // overrides as done for `hosts`.
+                // don't run any host-only tests.
                 if self.build.flags.host.len() > 0 {
-                    &self.build.flags.host[..]
+                    &self.build.hosts
                 } else if self.build.flags.target.len() > 0 {
                     &[]
                 } else if rule.only_build {
-                    &self.build.config.host[..1]
+                    self.build.build_slice()
                 } else {
-                    &self.build.config.host[..]
+                    &self.build.hosts
                 }
             } else {
-                targets
+                &self.build.targets
             };
 
             hosts.iter().flat_map(move |host| {
@@ -1326,7 +1318,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
         for idx in 0..nodes.len() {
             self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order);
         }
-        return order
+        order
     }
 
     /// Builds the dependency graph rooted at `step`.
@@ -1365,7 +1357,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
         }
 
         edges.entry(idx).or_insert(HashSet::new()).extend(deps);
-        return idx
+        idx
     }
 
     /// Given a dependency graph with a finished list of `nodes`, fill out more
@@ -1494,8 +1486,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         assert!(plan.contains(&step.name("dist-docs")));
@@ -1517,8 +1509,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         assert!(plan.contains(&step.name("dist-docs")));
@@ -1545,8 +1537,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         assert!(!plan.iter().any(|s| s.host == "B"));
@@ -1575,8 +1567,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         assert!(!plan.iter().any(|s| s.host == "B"));
@@ -1612,8 +1604,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         assert!(!plan.iter().any(|s| s.target == "A"));
@@ -1639,8 +1631,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         assert!(!plan.iter().any(|s| s.target == "A"));
@@ -1683,8 +1675,8 @@ mod tests {
         let step = super::Step {
             name: "",
             stage: 2,
-            host: &build.config.build,
-            target: &build.config.build,
+            host: &build.build,
+            target: &build.build,
         };
 
         // rustc built for all for of (A, B) x (A, B)
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 61bd85e76c598..092fb04637ba7 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -14,7 +14,6 @@
 //! not a lot of interesting happenings here unfortunately.
 
 use std::env;
-use std::ffi::OsString;
 use std::fs;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
@@ -32,16 +31,9 @@ pub fn staticlib(name: &str, target: &str) -> String {
     }
 }
 
-/// Copies a file from `src` to `dst`, attempting to use hard links and then
-/// falling back to an actually filesystem copy if necessary.
+/// Copies a file from `src` to `dst`
 pub fn copy(src: &Path, dst: &Path) {
-    // A call to `hard_link` will fail if `dst` exists, so remove it if it
-    // already exists so we can try to help `hard_link` succeed.
     let _ = fs::remove_file(&dst);
-
-    // Attempt to "easy copy" by creating a hard link (symlinks don't work on
-    // windows), but if that fails just fall back to a slow `copy` operation.
-    // let res = fs::hard_link(src, dst);
     let res = fs::copy(src, dst);
     if let Err(e) = res {
         panic!("failed to copy `{}` to `{}`: {}", src.display(),
@@ -149,8 +141,7 @@ pub fn dylib_path_var() -> &'static str {
 /// Parses the `dylib_path_var()` environment variable, returning a list of
 /// paths that are members of this lookup path.
 pub fn dylib_path() -> Vec<PathBuf> {
-    env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new()))
-        .collect()
+    env::split_paths(&env::var_os(dylib_path_var()).unwrap_or_default()).collect()
 }
 
 /// `push` all components to `buf`. On windows, append `.exe` to the last component.
@@ -422,4 +413,4 @@ impl CiEnv {
             cmd.env("TERM", "xterm").args(&["--color", "always"]);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index ea6a822e360a4..7011261ab6c16 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -239,7 +239,10 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoiler
         ),
         _ => return Err(()),
     };
-    native_lib_boilerplate("compiler-rt", sanitizer_name, &link_name, search_path)
+    native_lib_boilerplate("libcompiler_builtins/compiler-rt",
+                           sanitizer_name,
+                           &link_name,
+                           search_path)
 }
 
 fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh
index 817ed8dd55437..f8e86986f82d0 100755
--- a/src/ci/init_repo.sh
+++ b/src/ci/init_repo.sh
@@ -67,13 +67,14 @@ for module in $modules; do
         mv "src/llvm-$commit" src/llvm
         continue
     fi
-    if [ ! -d "$cache_src_dir/$module" ]; then
+    if [ ! -e "$cache_src_dir/$module/.git" ]; then
         echo "WARNING: $module not found in pristine repo"
-        retry sh -c "git submodule deinit -f $module && git submodule update --init $module"
+        retry sh -c "git submodule deinit -f $module && \
+            git submodule update --init --recursive $module"
         continue
     fi
     retry sh -c "git submodule deinit -f $module && \
-        git submodule update --init --reference $cache_src_dir/$module $module"
+        git submodule update --init --recursive --reference $cache_src_dir/$module $module"
 done
 
 travis_fold end update_submodules
diff --git a/src/compiler-rt b/src/compiler-rt
deleted file mode 160000
index c8a8767c56ad3..0000000000000
--- a/src/compiler-rt
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35
diff --git a/src/doc/unstable-book/src/language-features/allocator-internals.md b/src/doc/unstable-book/src/language-features/allocator-internals.md
new file mode 100644
index 0000000000000..2023d758fe3de
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/allocator-internals.md
@@ -0,0 +1,7 @@
+# `allocator_internals`
+
+This feature does not have a tracking issue, it is an unstable implementation
+detail of the `global_allocator` feature not intended for use outside the
+compiler.
+
+------------------------
diff --git a/src/doc/unstable-book/src/language-features/allocator.md b/src/doc/unstable-book/src/language-features/allocator.md
deleted file mode 100644
index cfcf8e22d7088..0000000000000
--- a/src/doc/unstable-book/src/language-features/allocator.md
+++ /dev/null
@@ -1,119 +0,0 @@
-# `allocator`
-
-The tracking issue for this feature is: [#27389]
-
-[#27389]: https://github.com/rust-lang/rust/issues/27389
-
-------------------------
-
-Sometimes even the choices of jemalloc vs the system allocator aren't enough and
-an entirely new custom allocator is required. In this you'll write your own
-crate which implements the allocator API (e.g. the same as `alloc_system` or
-`alloc_jemalloc`). As an example, let's take a look at a simplified and
-annotated version of `alloc_system`
-
-```rust,no_run
-# // Only needed for rustdoc --test down below.
-# #![feature(lang_items)]
-// The compiler needs to be instructed that this crate is an allocator in order
-// to realize that when this is linked in another allocator like jemalloc should
-// not be linked in.
-#![feature(allocator)]
-#![allocator]
-
-// Allocators are not allowed to depend on the standard library which in turn
-// requires an allocator in order to avoid circular dependencies. This crate,
-// however, can use all of libcore.
-#![no_std]
-
-// Let's give a unique name to our custom allocator:
-#![crate_name = "my_allocator"]
-#![crate_type = "rlib"]
-
-// Our system allocator will use the in-tree libc crate for FFI bindings. Note
-// that currently the external (crates.io) libc cannot be used because it links
-// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why
-// this specifically requires the in-tree version.
-#![feature(libc)]
-extern crate libc;
-
-// Listed below are the five allocation functions currently required by custom
-// allocators. Their signatures and symbol names are not currently typechecked
-// by the compiler, but this is a future extension and are required to match
-// what is found below.
-//
-// Note that the standard `malloc` and `realloc` functions do not provide a way
-// to communicate alignment so this implementation would need to be improved
-// with respect to alignment in that aspect.
-
-#[no_mangle]
-pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
-    unsafe { libc::malloc(size as libc::size_t) as *mut u8 }
-}
-
-#[no_mangle]
-pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 {
-    unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 }
-}
-
-#[no_mangle]
-pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
-    unsafe { libc::free(ptr as *mut libc::c_void) }
-}
-
-#[no_mangle]
-pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
-                                _align: usize) -> *mut u8 {
-    unsafe {
-        libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
-    }
-}
-
-#[no_mangle]
-pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
-                                        _size: usize, _align: usize) -> usize {
-    old_size // This api is not supported by libc.
-}
-
-#[no_mangle]
-pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
-    size
-}
-
-# // Only needed to get rustdoc to test this:
-# fn main() {}
-# #[lang = "panic_fmt"] fn panic_fmt() {}
-# #[lang = "eh_personality"] fn eh_personality() {}
-# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
-```
-
-After we compile this crate, it can be used as follows:
-
-```rust,ignore
-extern crate my_allocator;
-
-fn main() {
-    let a = Box::new(8); // Allocates memory via our custom allocator crate.
-    println!("{}", a);
-}
-```
-
-## Custom allocator limitations
-
-There are a few restrictions when working with custom allocators which may cause
-compiler errors:
-
-* Any one artifact may only be linked to at most one allocator. Binaries,
-  dylibs, and staticlibs must link to exactly one allocator, and if none have
-  been explicitly chosen the compiler will choose one. On the other hand rlibs
-  do not need to link to an allocator (but still can).
-
-* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the
-  `liballoc` crate currently) and an `#[allocator]` crate cannot transitively
-  depend on a crate which needs an allocator (e.g. circular dependencies are not
-  allowed). This basically means that allocators must restrict themselves to
-  libcore currently.
-
-
diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md
new file mode 100644
index 0000000000000..2eae40aef349e
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/global-allocator.md
@@ -0,0 +1,71 @@
+# `global_allocator`
+
+The tracking issue for this feature is: [#27389]
+
+[#27389]: https://github.com/rust-lang/rust/issues/27389
+
+------------------------
+
+Rust programs may need to change the allocator that they're running with from
+time to time. This use case is distinct from an allocator-per-collection (e.g. a
+`Vec` with a custom allocator) and instead is more related to changing the
+global default allocator, e.g. what `Vec<T>` uses by default.
+
+Currently Rust programs don't have a specified global allocator. The compiler
+may link to a version of [jemalloc] on some platforms, but this is not
+guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed
+to use the "system allocator" which means something like `malloc` on Unixes and
+`HeapAlloc` on Windows.
+
+[jemalloc]: https://github.com/jemalloc/jemalloc
+
+The `#[global_allocator]` attribute, however, allows configuring this choice.
+You can use this to implement a completely custom global allocator to route all
+default allocation requests to a custom object. Defined in [RFC 1974] usage
+looks like:
+
+[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974
+
+```rust
+#![feature(global_allocator, heap_api)]
+
+use std::heap::{Alloc, System, Layout, AllocErr};
+
+struct MyAllocator;
+
+unsafe impl<'a> Alloc for &'a MyAllocator {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        System.alloc(layout)
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        System.dealloc(ptr, layout)
+    }
+}
+
+#[global_allocator]
+static GLOBAL: MyAllocator = MyAllocator;
+
+fn main() {
+    // This `Vec` will allocate memory through `GLOBAL` above
+    let mut v = Vec::new();
+    v.push(1);
+}
+```
+
+And that's it! The `#[global_allocator]` attribute is applied to a `static`
+which implements the `Alloc` trait in the `std::heap` module. Note, though,
+that the implementation is defined for `&MyAllocator`, not just `MyAllocator`.
+You may wish, however, to also provide `Alloc for MyAllocator` for other use
+cases.
+
+A crate can only have one instance of `#[global_allocator]` and this instance
+may be loaded through a dependency. For example `#[global_allocator]` above
+could have been placed in one of the dependencies loaded through `extern crate`.
+
+Note that `Alloc` itself is an `unsafe` trait, with much documentation on the
+trait itself about usage and for implementors. Extra care should be taken when
+implementing a global allocator as well as the allocator may be called from many
+portions of the standard library, such as the panicking routine. As a result it
+is highly recommended to not panic during allocation and work in as many
+situations with as few dependencies as possible as well.
diff --git a/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md b/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md
deleted file mode 100644
index 5da8968fd0ce2..0000000000000
--- a/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# `compiler_builtins_lib`
-
-The tracking issue for this feature is: None.
-
-------------------------
-
-This feature is required to link to the `compiler_builtins` crate which contains
-"compiler intrinsics". Compiler intrinsics are software implementations of basic
-operations like multiplication of `u64`s. These intrinsics are only required on
-platforms where these operations don't directly map to a hardware instruction.
-
-You should never need to explicitly link to the `compiler_builtins` crate when
-building "std" programs as `compiler_builtins` is already in the dependency
-graph of `std`. But you may need it when building `no_std` **binary** crates. If
-you get a *linker* error like:
-
-``` text
-$PWD/src/main.rs:11: undefined reference to `__aeabi_lmul'
-$PWD/src/main.rs:11: undefined reference to `__aeabi_uldivmod'
-```
-
-That means that you need to link to this crate.
-
-When you link to this crate, make sure it only appears once in your crate
-dependency graph. Also, it doesn't matter where in the dependency graph, you
-place the `compiler_builtins` crate.
-
-<!-- NOTE(ignore) doctests don't support `no_std` binaries -->
-
-``` rust,ignore
-#![feature(compiler_builtins_lib)]
-#![no_std]
-
-extern crate compiler_builtins;
-```
diff --git a/src/doc/unstable-book/src/library-features/proc-macro.md b/src/doc/unstable-book/src/library-features/proc-macro.md
new file mode 100644
index 0000000000000..19e7f663c7ac3
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/proc-macro.md
@@ -0,0 +1,7 @@
+# `proc_macro`
+
+The tracking issue for this feature is: [#38356]
+
+[#38356]: https://github.com/rust-lang/rust/issues/38356
+
+------------------------
diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs
index bf38629ed38a7..ca5388b470147 100644
--- a/src/liballoc/allocator.rs
+++ b/src/liballoc/allocator.rs
@@ -13,7 +13,7 @@
                       slightly, especially to possibly take into account the \
                       types being stored to make room for a future \
                       tracing garbage collector",
-            issue = "27700")]
+            issue = "32838")]
 
 use core::cmp;
 use core::fmt;
@@ -73,6 +73,7 @@ impl Layout {
     /// * `size`, when rounded up to the nearest multiple of `align`,
     ///    must not overflow (i.e. the rounded value must be less than
     ///    `usize::MAX`).
+    #[inline]
     pub fn from_size_align(size: usize, align: usize) -> Option<Layout> {
         if !align.is_power_of_two() {
             return None;
@@ -96,13 +97,28 @@ impl Layout {
             return None;
         }
 
-        Some(Layout { size: size, align: align })
+        unsafe {
+            Some(Layout::from_size_align_unchecked(size, align))
+        }
+    }
+
+    /// Creates a layout, bypassing all checks.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe as it does not verify that `align` is a power of
+    /// two nor that `size` aligned to `align` fits within the address space.
+    #[inline]
+    pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout {
+        Layout { size: size, align: align }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
+    #[inline]
     pub fn size(&self) -> usize { self.size }
 
     /// The minimum byte alignment for a memory block of this layout.
+    #[inline]
     pub fn align(&self) -> usize { self.align }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -135,6 +151,7 @@ impl Layout {
     ///
     /// Panics if the combination of `self.size` and the given `align`
     /// violates the conditions listed in `from_size_align`.
+    #[inline]
     pub fn align_to(&self, align: usize) -> Self {
         Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap()
     }
@@ -155,6 +172,7 @@ impl Layout {
     /// to be less than or equal to the alignment of the starting
     /// address for the whole allocated block of memory. One way to
     /// satisfy this constraint is to ensure `align <= self.align`.
+    #[inline]
     pub fn padding_needed_for(&self, align: usize) -> usize {
         let len = self.size();
 
@@ -556,6 +574,7 @@ pub unsafe trait Alloc {
     /// However, for clients that do not wish to track the capacity
     /// returned by `alloc_excess` locally, this method is likely to
     /// produce useful results.
+    #[inline]
     fn usable_size(&self, layout: &Layout) -> (usize, usize) {
         (layout.size(), layout.size())
     }
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 7c51c4b161ca8..d9edf50b9c8ec 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -23,7 +23,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 use core::borrow;
 use core::fmt;
 use core::cmp::Ordering;
-use core::mem::{align_of_val, size_of_val};
 use core::intrinsics::abort;
 use core::mem;
 use core::mem::uninitialized;
@@ -34,7 +33,8 @@ use core::marker::Unsize;
 use core::hash::{Hash, Hasher};
 use core::{isize, usize};
 use core::convert::From;
-use heap::deallocate;
+
+use heap::{Heap, Alloc, Layout};
 
 /// A soft limit on the amount of references that may be made to an `Arc`.
 ///
@@ -503,7 +503,7 @@ impl<T: ?Sized> Arc<T> {
 
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             atomic::fence(Acquire);
-            deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
+            Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr))
         }
     }
 
@@ -1007,7 +1007,9 @@ impl<T: ?Sized> Drop for Weak<T> {
         // ref, which can only happen after the lock is released.
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             atomic::fence(Acquire);
-            unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) }
+            unsafe {
+                Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr))
+            }
         }
     }
 }
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 4a43018e973b1..76cf10f0d55ea 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -55,7 +55,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use heap;
+use heap::{Heap, Layout, Alloc};
 use raw_vec::RawVec;
 
 use core::any::Any;
@@ -135,8 +135,7 @@ pub struct Box<T: ?Sized>(Unique<T>);
 #[allow(missing_debug_implementations)]
 pub struct IntermediateBox<T: ?Sized> {
     ptr: *mut u8,
-    size: usize,
-    align: usize,
+    layout: Layout,
     marker: marker::PhantomData<*mut T>,
 }
 
@@ -156,23 +155,21 @@ unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
 }
 
 fn make_place<T>() -> IntermediateBox<T> {
-    let size = mem::size_of::<T>();
-    let align = mem::align_of::<T>();
+    let layout = Layout::new::<T>();
 
-    let p = if size == 0 {
+    let p = if layout.size() == 0 {
         mem::align_of::<T>() as *mut u8
     } else {
-        let p = unsafe { heap::allocate(size, align) };
-        if p.is_null() {
-            panic!("Box make_place allocation failure.");
+        unsafe {
+            Heap.alloc(layout.clone()).unwrap_or_else(|err| {
+                Heap.oom(err)
+            })
         }
-        p
     };
 
     IntermediateBox {
         ptr: p,
-        size: size,
-        align: align,
+        layout: layout,
         marker: marker::PhantomData,
     }
 }
@@ -221,8 +218,10 @@ impl<T> Placer<T> for ExchangeHeapSingleton {
            issue = "27779")]
 impl<T: ?Sized> Drop for IntermediateBox<T> {
     fn drop(&mut self) {
-        if self.size > 0 {
-            unsafe { heap::deallocate(self.ptr, self.size, self.align) }
+        if self.layout.size() > 0 {
+            unsafe {
+                Heap.dealloc(self.ptr, self.layout.clone())
+            }
         }
     }
 }
diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs
index 811174b331e2b..0eaff6f2192c8 100644
--- a/src/liballoc/btree/node.rs
+++ b/src/liballoc/btree/node.rs
@@ -48,7 +48,7 @@ use core::ptr::{self, Unique};
 use core::slice;
 
 use boxed::Box;
-use heap;
+use heap::{Heap, Alloc, Layout};
 
 const B: usize = 6;
 pub const MIN_LEN: usize = B - 1;
@@ -254,11 +254,7 @@ impl<K, V> Root<K, V> {
         self.as_mut().as_leaf_mut().parent = ptr::null();
 
         unsafe {
-            heap::deallocate(
-                top,
-                mem::size_of::<InternalNode<K, V>>(),
-                mem::align_of::<InternalNode<K, V>>()
-            );
+            Heap.dealloc(top, Layout::new::<InternalNode<K, V>>());
         }
     }
 }
@@ -445,7 +441,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
     > {
         let ptr = self.as_leaf() as *const LeafNode<K, V> as *const u8 as *mut u8;
         let ret = self.ascend().ok();
-        heap::deallocate(ptr, mem::size_of::<LeafNode<K, V>>(), mem::align_of::<LeafNode<K, V>>());
+        Heap.dealloc(ptr, Layout::new::<LeafNode<K, V>>());
         ret
     }
 }
@@ -466,11 +462,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
     > {
         let ptr = self.as_internal() as *const InternalNode<K, V> as *const u8 as *mut u8;
         let ret = self.ascend().ok();
-        heap::deallocate(
-            ptr,
-            mem::size_of::<InternalNode<K, V>>(),
-            mem::align_of::<InternalNode<K, V>>()
-        );
+        Heap.dealloc(ptr, Layout::new::<InternalNode<K, V>>());
         ret
     }
 }
@@ -1252,16 +1244,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
                     ).correct_parent_link();
                 }
 
-                heap::deallocate(
+                Heap.dealloc(
                     right_node.node.get() as *mut u8,
-                    mem::size_of::<InternalNode<K, V>>(),
-                    mem::align_of::<InternalNode<K, V>>()
+                    Layout::new::<InternalNode<K, V>>(),
                 );
             } else {
-                heap::deallocate(
+                Heap.dealloc(
                     right_node.node.get() as *mut u8,
-                    mem::size_of::<LeafNode<K, V>>(),
-                    mem::align_of::<LeafNode<K, V>>()
+                    Layout::new::<LeafNode<K, V>>(),
                 );
             }
 
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
index d46c6a83ff32c..1d959ac5bf6dc 100644
--- a/src/liballoc/heap.rs
+++ b/src/liballoc/heap.rs
@@ -8,207 +8,212 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![unstable(feature = "heap_api",
+#![unstable(feature = "allocator_api",
             reason = "the precise API and guarantees it provides may be tweaked \
                       slightly, especially to possibly take into account the \
                       types being stored to make room for a future \
                       tracing garbage collector",
-            issue = "27700")]
+            issue = "32838")]
 
-use allocator::{Alloc, AllocErr, CannotReallocInPlace, Layout};
-use core::{isize, usize, cmp, ptr};
 use core::intrinsics::{min_align_of_val, size_of_val};
+use core::mem::{self, ManuallyDrop};
+use core::usize;
 
-#[allow(improper_ctypes)]
-extern "C" {
-    #[allocator]
-    fn __rust_allocate(size: usize, align: usize) -> *mut u8;
-    fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8;
-    fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
-    fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
-    fn __rust_reallocate_inplace(ptr: *mut u8,
-                                 old_size: usize,
-                                 size: usize,
-                                 align: usize)
-                                 -> usize;
-    fn __rust_usable_size(size: usize, align: usize) -> usize;
+pub use allocator::*;
+#[doc(hidden)]
+pub mod __core {
+    pub use core::*;
 }
 
-#[inline(always)]
-fn check_size_and_alignment(size: usize, align: usize) {
-    debug_assert!(size != 0);
-    debug_assert!(size <= isize::MAX as usize,
-                  "Tried to allocate too much: {} bytes",
-                  size);
-    debug_assert!(usize::is_power_of_two(align),
-                  "Invalid alignment of allocation: {}",
-                  align);
+extern "Rust" {
+    #[allocator]
+    fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
+    fn __rust_oom(err: *const u8) -> !;
+    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
+    fn __rust_usable_size(layout: *const u8,
+                          min: *mut usize,
+                          max: *mut usize);
+    fn __rust_realloc(ptr: *mut u8,
+                      old_size: usize,
+                      old_align: usize,
+                      new_size: usize,
+                      new_align: usize,
+                      err: *mut u8) -> *mut u8;
+    fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
+    fn __rust_alloc_excess(size: usize,
+                           align: usize,
+                           excess: *mut usize,
+                           err: *mut u8) -> *mut u8;
+    fn __rust_realloc_excess(ptr: *mut u8,
+                             old_size: usize,
+                             old_align: usize,
+                             new_size: usize,
+                             new_align: usize,
+                             excess: *mut usize,
+                             err: *mut u8) -> *mut u8;
+    fn __rust_grow_in_place(ptr: *mut u8,
+                            old_size: usize,
+                            old_align: usize,
+                            new_size: usize,
+                            new_align: usize) -> u8;
+    fn __rust_shrink_in_place(ptr: *mut u8,
+                              old_size: usize,
+                              old_align: usize,
+                              new_size: usize,
+                              new_align: usize) -> u8;
 }
 
 #[derive(Copy, Clone, Default, Debug)]
-pub struct HeapAlloc;
+pub struct Heap;
 
-unsafe impl Alloc for HeapAlloc {
+unsafe impl Alloc for Heap {
+    #[inline]
     unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        let addr = allocate(layout.size(), layout.align());
-        if addr.is_null() {
-            Err(AllocErr::Exhausted { request: layout })
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let ptr = __rust_alloc(layout.size(),
+                               layout.align(),
+                               &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
         } else {
-            Ok(addr)
+            Ok(ptr)
         }
     }
 
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        let addr = allocate_zeroed(layout.size(), layout.align());
-        if addr.is_null() {
-            Err(AllocErr::Exhausted { request: layout })
-        } else {
-            Ok(addr)
+    #[inline]
+    fn oom(&mut self, err: AllocErr) -> ! {
+        unsafe {
+            __rust_oom(&err as *const AllocErr as *const u8)
         }
     }
 
+    #[inline]
     unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
-        deallocate(ptr, layout.size(), layout.align());
+        __rust_dealloc(ptr, layout.size(), layout.align())
     }
 
+    #[inline]
     fn usable_size(&self, layout: &Layout) -> (usize, usize) {
-        (layout.size(), usable_size(layout.size(), layout.align()))
+        let mut min = 0;
+        let mut max = 0;
+        unsafe {
+            __rust_usable_size(layout as *const Layout as *const u8,
+                               &mut min,
+                               &mut max);
+        }
+        (min, max)
     }
 
+    #[inline]
     unsafe fn realloc(&mut self,
                       ptr: *mut u8,
                       layout: Layout,
                       new_layout: Layout)
                       -> Result<*mut u8, AllocErr>
     {
-        let old_size = layout.size();
-        let new_size = new_layout.size();
-        if layout.align() == new_layout.align() {
-            let new_ptr = reallocate(ptr, old_size, new_size, layout.align());
-            if new_ptr.is_null() {
-                // We assume `reallocate` already tried alloc + copy +
-                // dealloc fallback; thus pointless to repeat effort
-                Err(AllocErr::Exhausted { request: new_layout })
-            } else {
-                Ok(new_ptr)
-            }
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let ptr = __rust_realloc(ptr,
+                                 layout.size(),
+                                 layout.align(),
+                                 new_layout.size(),
+                                 new_layout.align(),
+                                 &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
         } else {
-            // if alignments don't match, fall back on alloc + copy + dealloc
-            let result = self.alloc(new_layout);
-            if let Ok(new_ptr) = result {
-                ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size));
-                self.dealloc(ptr, layout);
-            }
-            result
+            mem::forget(err);
+            Ok(ptr)
         }
     }
 
+    #[inline]
+    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let ptr = __rust_alloc_zeroed(layout.size(),
+                                      layout.align(),
+                                      &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
+        } else {
+            Ok(ptr)
+        }
+    }
+
+    #[inline]
+    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let mut size = 0;
+        let ptr = __rust_alloc_excess(layout.size(),
+                                      layout.align(),
+                                      &mut size,
+                                      &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
+        } else {
+            Ok(Excess(ptr, size))
+        }
+    }
+
+    #[inline]
+    unsafe fn realloc_excess(&mut self,
+                             ptr: *mut u8,
+                             layout: Layout,
+                             new_layout: Layout) -> Result<Excess, AllocErr> {
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let mut size = 0;
+        let ptr = __rust_realloc_excess(ptr,
+                                        layout.size(),
+                                        layout.align(),
+                                        new_layout.size(),
+                                        new_layout.align(),
+                                        &mut size,
+                                        &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
+        } else {
+            Ok(Excess(ptr, size))
+        }
+    }
+
+    #[inline]
     unsafe fn grow_in_place(&mut self,
                             ptr: *mut u8,
                             layout: Layout,
                             new_layout: Layout)
                             -> Result<(), CannotReallocInPlace>
     {
-        // grow_in_place spec requires this, and the spec for reallocate_inplace
-        // makes it hard to detect failure if it does not hold.
         debug_assert!(new_layout.size() >= layout.size());
-
-        if layout.align() != new_layout.align() { // reallocate_inplace requires this.
-            return Err(CannotReallocInPlace);
+        debug_assert!(new_layout.align() == layout.align());
+        let ret = __rust_grow_in_place(ptr,
+                                       layout.size(),
+                                       layout.align(),
+                                       new_layout.size(),
+                                       new_layout.align());
+        if ret != 0 {
+            Ok(())
+        } else {
+            Err(CannotReallocInPlace)
         }
-        let usable = reallocate_inplace(ptr, layout.size(), new_layout.size(), layout.align());
-        if usable >= new_layout.size() { Ok(()) } else { Err(CannotReallocInPlace) }
     }
-}
-
-// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
 
-/// Return a pointer to `size` bytes of memory aligned to `align`.
-///
-/// On failure, return a null pointer.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-#[inline]
-pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-    check_size_and_alignment(size, align);
-    __rust_allocate(size, align)
-}
-
-/// Return a pointer to `size` bytes of memory aligned to `align` and
-/// initialized to zeroes.
-///
-/// On failure, return a null pointer.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-#[inline]
-pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-    check_size_and_alignment(size, align);
-    __rust_allocate_zeroed(size, align)
-}
-
-/// Resize the allocation referenced by `ptr` to `size` bytes.
-///
-/// On failure, return a null pointer and leave the original allocation intact.
-///
-/// If the allocation was relocated, the memory at the passed-in pointer is
-/// undefined after the call.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-///
-/// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may be
-/// any value in range_inclusive(requested_size, usable_size).
-#[inline]
-pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
-    check_size_and_alignment(size, align);
-    __rust_reallocate(ptr, old_size, size, align)
-}
-
-/// Resize the allocation referenced by `ptr` to `size` bytes.
-///
-/// If the operation succeeds, it returns `usable_size(size, align)` and if it
-/// fails (or is a no-op) it returns `usable_size(old_size, align)`.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-///
-/// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may be
-/// any value in range_inclusive(requested_size, usable_size).
-#[inline]
-pub unsafe fn reallocate_inplace(ptr: *mut u8,
-                                 old_size: usize,
-                                 size: usize,
-                                 align: usize)
-                                 -> usize {
-    check_size_and_alignment(size, align);
-    __rust_reallocate_inplace(ptr, old_size, size, align)
-}
-
-/// Deallocates the memory referenced by `ptr`.
-///
-/// The `ptr` parameter must not be null.
-///
-/// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may be
-/// any value in range_inclusive(requested_size, usable_size).
-#[inline]
-pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
-    __rust_deallocate(ptr, old_size, align)
-}
-
-/// Returns the usable size of an allocation created with the specified the
-/// `size` and `align`.
-#[inline]
-pub fn usable_size(size: usize, align: usize) -> usize {
-    unsafe { __rust_usable_size(size, align) }
+    #[inline]
+    unsafe fn shrink_in_place(&mut self,
+                              ptr: *mut u8,
+                              layout: Layout,
+                              new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+        debug_assert!(new_layout.size() <= layout.size());
+        debug_assert!(new_layout.align() == layout.align());
+        let ret = __rust_shrink_in_place(ptr,
+                                         layout.size(),
+                                         layout.align(),
+                                         new_layout.size(),
+                                         new_layout.align());
+        if ret != 0 {
+            Ok(())
+        } else {
+            Err(CannotReallocInPlace)
+        }
+    }
 }
 
 /// An arbitrary non-null address to represent zero-size allocations.
@@ -228,11 +233,10 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     if size == 0 {
         align as *mut u8
     } else {
-        let ptr = allocate(size, align);
-        if ptr.is_null() {
-            ::oom()
-        }
-        ptr
+        let layout = Layout::from_size_align_unchecked(size, align);
+        Heap.alloc(layout).unwrap_or_else(|err| {
+            Heap.oom(err)
+        })
     }
 }
 
@@ -243,7 +247,8 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
     let align = min_align_of_val(&*ptr);
     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
     if size != 0 {
-        deallocate(ptr as *mut u8, size, align);
+        let layout = Layout::from_size_align_unchecked(size, align);
+        Heap.dealloc(ptr as *mut u8, layout);
     }
 }
 
@@ -252,38 +257,22 @@ mod tests {
     extern crate test;
     use self::test::Bencher;
     use boxed::Box;
-    use heap;
+    use heap::{Heap, Alloc, Layout};
 
     #[test]
     fn allocate_zeroed() {
         unsafe {
-            let size = 1024;
-            let ptr = heap::allocate_zeroed(size, 1);
-            if ptr.is_null() {
-                ::oom()
-            }
+            let layout = Layout::from_size_align(1024, 1).unwrap();
+            let ptr = Heap.alloc_zeroed(layout.clone())
+                .unwrap_or_else(|e| Heap.oom(e));
 
-            let end = ptr.offset(size as isize);
+            let end = ptr.offset(layout.size() as isize);
             let mut i = ptr;
             while i < end {
                 assert_eq!(*i, 0);
                 i = i.offset(1);
             }
-            heap::deallocate(ptr, size, 1);
-        }
-    }
-
-    #[test]
-    fn basic_reallocate_inplace_noop() {
-        unsafe {
-            let size = 4000;
-            let ptr = heap::allocate(size, 8);
-            if ptr.is_null() {
-                ::oom()
-            }
-            let ret = heap::reallocate_inplace(ptr, size, size, 8);
-            heap::deallocate(ptr, size, 8);
-            assert_eq!(ret, heap::usable_size(size, 8));
+            Heap.dealloc(ptr, layout);
         }
     }
 
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 23da29131362e..b419aeb5ab593 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -85,7 +85,7 @@
 #![cfg_attr(not(test), feature(slice_rotate))]
 #![cfg_attr(not(test), feature(str_checked_slicing))]
 #![cfg_attr(test, feature(rand, test))]
-#![feature(allocator)]
+#![cfg_attr(stage0, feature(allocator))]
 #![feature(allow_internal_unstable)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
@@ -124,6 +124,7 @@
 #![feature(unicode)]
 #![feature(unique)]
 #![feature(unsize)]
+#![cfg_attr(not(stage0), feature(allocator_internals))]
 
 #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
 #![cfg_attr(test, feature(test, box_heap))]
@@ -168,7 +169,6 @@ mod boxed_test;
 pub mod arc;
 pub mod rc;
 pub mod raw_vec;
-pub mod oom;
 
 // collections modules
 pub mod binary_heap;
@@ -260,8 +260,6 @@ trait SpecExtend<I: IntoIterator> {
     fn spec_extend(&mut self, iter: I);
 }
 
-pub use oom::oom;
-
 #[doc(no_inline)]
 pub use binary_heap::BinaryHeap;
 #[doc(no_inline)]
diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs
deleted file mode 100644
index 3640156fec2ae..0000000000000
--- a/src/liballoc/oom.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014-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.
-
-#[cfg(target_has_atomic = "ptr")]
-pub use self::imp::set_oom_handler;
-use core::intrinsics;
-
-fn default_oom_handler() -> ! {
-    // The default handler can't do much more since we can't assume the presence
-    // of libc or any way of printing an error message.
-    unsafe { intrinsics::abort() }
-}
-
-/// Common out-of-memory routine
-#[cold]
-#[inline(never)]
-#[unstable(feature = "oom", reason = "not a scrutinized interface",
-           issue = "27700")]
-pub fn oom() -> ! {
-    self::imp::oom()
-}
-
-#[cfg(target_has_atomic = "ptr")]
-mod imp {
-    use core::mem;
-    use core::sync::atomic::{AtomicPtr, Ordering};
-
-    static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(super::default_oom_handler as *mut ());
-
-    #[inline(always)]
-    pub fn oom() -> ! {
-        let value = OOM_HANDLER.load(Ordering::SeqCst);
-        let handler: fn() -> ! = unsafe { mem::transmute(value) };
-        handler();
-    }
-
-    /// Set a custom handler for out-of-memory conditions
-    ///
-    /// To avoid recursive OOM failures, it is critical that the OOM handler does
-    /// not allocate any memory itself.
-    #[unstable(feature = "oom", reason = "not a scrutinized interface",
-               issue = "27700")]
-    pub fn set_oom_handler(handler: fn() -> !) {
-        OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst);
-    }
-}
-
-#[cfg(not(target_has_atomic = "ptr"))]
-mod imp {
-    #[inline(always)]
-    pub fn oom() -> ! {
-        super::default_oom_handler()
-    }
-}
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index c56a93c046041..d1aab4c70be4a 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -12,7 +12,7 @@ use allocator::{Alloc, Layout};
 use core::ptr::{self, Unique};
 use core::mem;
 use core::slice;
-use heap::{HeapAlloc};
+use heap::Heap;
 use super::boxed::Box;
 use core::ops::Drop;
 use core::cmp;
@@ -45,7 +45,7 @@ use core::cmp;
 /// field. This allows zero-sized types to not be special-cased by consumers of
 /// this type.
 #[allow(missing_debug_implementations)]
-pub struct RawVec<T, A: Alloc = HeapAlloc> {
+pub struct RawVec<T, A: Alloc = Heap> {
     ptr: Unique<T>,
     cap: usize,
     a: A,
@@ -112,14 +112,14 @@ impl<T, A: Alloc> RawVec<T, A> {
     }
 }
 
-impl<T> RawVec<T, HeapAlloc> {
+impl<T> RawVec<T, Heap> {
     /// Creates the biggest possible RawVec (on the system heap)
     /// without allocating. If T has positive size, then this makes a
     /// RawVec with capacity 0. If T has 0 size, then it it makes a
     /// RawVec with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     pub fn new() -> Self {
-        Self::new_in(HeapAlloc)
+        Self::new_in(Heap)
     }
 
     /// Creates a RawVec (on the system heap) with exactly the
@@ -139,13 +139,13 @@ impl<T> RawVec<T, HeapAlloc> {
     /// Aborts on OOM
     #[inline]
     pub fn with_capacity(cap: usize) -> Self {
-        RawVec::allocate_in(cap, false, HeapAlloc)
+        RawVec::allocate_in(cap, false, Heap)
     }
 
     /// Like `with_capacity` but guarantees the buffer is zeroed.
     #[inline]
     pub fn with_capacity_zeroed(cap: usize) -> Self {
-        RawVec::allocate_in(cap, true, HeapAlloc)
+        RawVec::allocate_in(cap, true, Heap)
     }
 }
 
@@ -166,7 +166,7 @@ impl<T, A: Alloc> RawVec<T, A> {
     }
 }
 
-impl<T> RawVec<T, HeapAlloc> {
+impl<T> RawVec<T, Heap> {
     /// Reconstitutes a RawVec from a pointer, capacity.
     ///
     /// # Undefined Behavior
@@ -178,7 +178,7 @@ impl<T> RawVec<T, HeapAlloc> {
         RawVec {
             ptr: Unique::new(ptr),
             cap: cap,
-            a: HeapAlloc,
+            a: Heap,
         }
     }
 
@@ -609,7 +609,7 @@ impl<T, A: Alloc> RawVec<T, A> {
     }
 }
 
-impl<T> RawVec<T, HeapAlloc> {
+impl<T> RawVec<T, Heap> {
     /// Converts the entire buffer into `Box<[T]>`.
     ///
     /// While it is not *strictly* Undefined Behavior to call
@@ -693,13 +693,13 @@ mod tests {
                 if size > self.fuel {
                     return Err(AllocErr::Unsupported { details: "fuel exhausted" });
                 }
-                match HeapAlloc.alloc(layout) {
+                match Heap.alloc(layout) {
                     ok @ Ok(_) => { self.fuel -= size; ok }
                     err @ Err(_) => err,
                 }
             }
             unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
-                HeapAlloc.dealloc(ptr, layout)
+                Heap.dealloc(ptr, layout)
             }
         }
 
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 94fe36d01a5a5..306136b21c84b 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -252,13 +252,13 @@ use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
 use core::marker;
 use core::marker::Unsize;
-use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
+use core::mem::{self, forget, size_of, size_of_val, uninitialized};
 use core::ops::Deref;
 use core::ops::CoerceUnsized;
 use core::ptr::{self, Shared};
 use core::convert::From;
 
-use heap::{allocate, deallocate, box_free};
+use heap::{Heap, Alloc, Layout, box_free};
 use raw_vec::RawVec;
 
 struct RcBox<T: ?Sized> {
@@ -461,7 +461,8 @@ impl<T> Rc<[T]> {
             // FIXME(custom-DST): creating this invalid &[T] is dubiously defined,
             // we should have a better way of getting the size/align
             // of a DST from its unsized part.
-            let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr));
+            let ptr = Heap.alloc(Layout::for_value(&*ptr))
+                .unwrap_or_else(|e| Heap.oom(e));
             let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]);
 
             // Initialize the new RcBox.
@@ -719,7 +720,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
                 self.dec_weak();
 
                 if self.weak() == 0 {
-                    deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
+                    Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr));
                 }
             }
         }
@@ -1097,7 +1098,7 @@ impl<T: ?Sized> Drop for Weak<T> {
             // the weak count starts at 1, and will only go to zero if all
             // the strong pointers have disappeared.
             if self.weak() == 0 {
-                deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
+                Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr));
             }
         }
     }
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 79d1ccf637d37..622cc68964bf7 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -2008,10 +2008,10 @@ impl From<Box<str>> for String {
     }
 }
 
-#[stable(feature = "box_from_str", since = "1.18.0")]
-impl Into<Box<str>> for String {
-    fn into(self) -> Box<str> {
-        self.into_boxed_str()
+#[stable(feature = "box_from_str", since = "1.20.0")]
+impl From<String> for Box<str> {
+    fn from(s: String) -> Box<str> {
+        s.into_boxed_str()
     }
 }
 
diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs
index fdf453b39cf5d..17f1229c2060e 100644
--- a/src/liballoc/tests/vec.rs
+++ b/src/liballoc/tests/vec.rs
@@ -274,6 +274,11 @@ fn test_dedup_by() {
     vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
 
     assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+
+    let mut vec = vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)];
+    vec.dedup_by(|a, b| a.0 == b.0 && { b.1 += a.1; true });
+
+    assert_eq!(vec, [("foo", 3), ("bar", 12)]);
 }
 
 #[test]
diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs
index a992351653d7b..f2935c05d4f7a 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -510,8 +510,7 @@ fn test_from_iter() {
     let u: Vec<_> = deq.iter().cloned().collect();
     assert_eq!(u, v);
 
-    // FIXME #27741: Remove `.skip(0)` when Range::step_by is fully removed
-    let seq = (0..).skip(0).step_by(2).take(256);
+    let seq = (0..).step_by(2).take(256);
     let deq: VecDeque<_> = seq.collect();
     for (i, &x) in deq.iter().enumerate() {
         assert_eq!(2 * i, x);
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 5d1999a42629a..780a51aec3bab 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -222,7 +222,7 @@ use Bound::{Excluded, Included, Unbounded};
 /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
 /// types inside a `Vec`, it will not allocate space for them. *Note that in this case
 /// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only
-/// if [`mem::size_of::<T>`]` * capacity() > 0`. In general, `Vec`'s allocation
+/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
 /// details are subtle enough that it is strongly recommended that you only
 /// free memory allocated by a `Vec` by creating a new `Vec` and dropping it.
 ///
@@ -823,7 +823,8 @@ impl<T> Vec<T> {
         }
     }
 
-    /// Removes consecutive elements in the vector that resolve to the same key.
+    /// Removes all but the first of consecutive elements in the vector that resolve to the same
+    /// key.
     ///
     /// If the vector is sorted, this removes all duplicates.
     ///
@@ -842,11 +843,13 @@ impl<T> Vec<T> {
         self.dedup_by(|a, b| key(a) == key(b))
     }
 
-    /// Removes consecutive elements in the vector according to a predicate.
+    /// Removes all but the first of consecutive elements in the vector satisfying a given equality
+    /// relation.
     ///
     /// The `same_bucket` function is passed references to two elements from the vector, and
-    /// returns `true` if the elements compare equal, or `false` if they do not. Only the first
-    /// of adjacent equal items is kept.
+    /// returns `true` if the elements compare equal, or `false` if they do not. The elements are
+    /// passed in opposite order from their order in the vector, so if `same_bucket(a, b)` returns
+    /// `true`, `a` is removed.
     ///
     /// If the vector is sorted, this removes all duplicates.
     ///
diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml
index 49e5baad74dda..99c0bf2aaab48 100644
--- a/src/liballoc_jemalloc/Cargo.toml
+++ b/src/liballoc_jemalloc/Cargo.toml
@@ -15,6 +15,10 @@ doc = false
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
 
+[target.'cfg(not(stage0))'.dependencies]
+alloc = { path = "../liballoc" }
+alloc_system = { path = "../liballoc_system" }
+
 [build-dependencies]
 build_helper = { path = "../build_helper" }
 gcc = "0.3.50"
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index 288531cb5b21f..72686ddcc09ef 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -11,23 +11,36 @@
 #![crate_name = "alloc_jemalloc"]
 #![crate_type = "rlib"]
 #![no_std]
-#![allocator]
 #![unstable(feature = "alloc_jemalloc",
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
             issue = "27783")]
 #![deny(warnings)]
-#![feature(allocator)]
 #![feature(libc)]
 #![feature(staged_api)]
-
+#![feature(linkage)]
+#![cfg_attr(stage0, allocator)]
+#![cfg_attr(stage0, feature(allocator))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
+#![cfg_attr(all(not(stage0), not(dummy_jemalloc)), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(alloc))]
+#![cfg_attr(not(stage0), feature(alloc_system))]
+#![cfg_attr(dummy_jemalloc, allow(dead_code))]
+
+#[cfg(not(stage0))]
+extern crate alloc;
+#[cfg(not(stage0))]
+extern crate alloc_system;
 extern crate libc;
 
-pub use imp::*;
+#[cfg(all(not(stage0), not(dummy_jemalloc)))]
+pub use contents::*;
+#[cfg(all(not(stage0), not(dummy_jemalloc)))]
+mod contents {
+    use core::ptr;
 
-// See comments in build.rs for why we sometimes build a crate that does nothing
-#[cfg(not(dummy_jemalloc))]
-mod imp {
+    use alloc::heap::{Alloc, AllocErr, Layout};
+    use alloc_system::System;
     use libc::{c_int, c_void, size_t};
 
     // Note that the symbols here are prefixed by default on macOS and Windows (we
@@ -91,96 +104,152 @@ mod imp {
         }
     }
 
-    #[no_mangle]
-    pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
-        let flags = align_to_flags(align);
-        unsafe { mallocx(size as size_t, flags) as *mut u8 }
-    }
+    // for symbol names src/librustc/middle/allocator.rs
+    // for signatures src/librustc_allocator/lib.rs
 
-    #[no_mangle]
-    pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            unsafe { calloc(size as size_t, 1) as *mut u8 }
-        } else {
-            let flags = align_to_flags(align) | MALLOCX_ZERO;
-            unsafe { mallocx(size as size_t, flags) as *mut u8 }
-        }
-    }
+    // linkage directives are provided as part of the current compiler allocator
+    // ABI
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate(ptr: *mut u8,
-                                        _old_size: usize,
-                                        size: usize,
-                                        align: usize)
-                                        -> *mut u8 {
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_alloc(size: usize,
+                                     align: usize,
+                                     err: *mut u8) -> *mut u8 {
         let flags = align_to_flags(align);
-        unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
+        let ptr = mallocx(size as size_t, flags) as *mut u8;
+        if ptr.is_null() {
+            let layout = Layout::from_size_align_unchecked(size, align);
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Exhausted { request: layout });
+        }
+        ptr
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
-                                                _old_size: usize,
-                                                size: usize,
-                                                align: usize)
-                                                -> usize {
-        let flags = align_to_flags(align);
-        unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
+        System.oom((*(err as *const AllocErr)).clone())
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
+                                       size: usize,
+                                       align: usize) {
         let flags = align_to_flags(align);
-        unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
+        sdallocx(ptr as *mut c_void, size, flags);
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
-        let flags = align_to_flags(align);
-        unsafe { nallocx(size as size_t, flags) as usize }
-    }
-}
-
-#[cfg(dummy_jemalloc)]
-mod imp {
-    fn bogus() -> ! {
-        panic!("jemalloc is not implemented for this platform");
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_usable_size(layout: *const u8,
+                                           min: *mut usize,
+                                           max: *mut usize) {
+        let layout = &*(layout as *const Layout);
+        let flags = align_to_flags(layout.align());
+        let size = nallocx(layout.size(), flags) as usize;
+        *min = layout.size();
+        if size > 0 {
+            *max = size;
+        } else {
+            *max = layout.size();
+        }
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_realloc(ptr: *mut u8,
+                                       _old_size: usize,
+                                       old_align: usize,
+                                       new_size: usize,
+                                       new_align: usize,
+                                       err: *mut u8) -> *mut u8 {
+        if new_align != old_align {
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Unsupported { details: "can't change alignments" });
+            return 0 as *mut u8
+        }
+
+        let flags = align_to_flags(new_align);
+        let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
+        if ptr.is_null() {
+            let layout = Layout::from_size_align_unchecked(new_size, new_align);
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Exhausted { request: layout });
+        }
+        ptr
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_allocate_zeroed(_size: usize, _align: usize) -> *mut u8 {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_alloc_zeroed(size: usize,
+                                            align: usize,
+                                            err: *mut u8) -> *mut u8 {
+        let ptr = if align <= MIN_ALIGN {
+            calloc(size as size_t, 1) as *mut u8
+        } else {
+            let flags = align_to_flags(align) | MALLOCX_ZERO;
+            mallocx(size as size_t, flags) as *mut u8
+        };
+        if ptr.is_null() {
+            let layout = Layout::from_size_align_unchecked(size, align);
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Exhausted { request: layout });
+        }
+        ptr
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
-                                        _old_size: usize,
-                                        _size: usize,
-                                        _align: usize)
-                                        -> *mut u8 {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_alloc_excess(size: usize,
+                                            align: usize,
+                                            excess: *mut usize,
+                                            err: *mut u8) -> *mut u8 {
+        let p = __rde_alloc(size, align, err);
+        if !p.is_null() {
+            *excess = size;
+        }
+        return p
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
-                                                _old_size: usize,
-                                                _size: usize,
-                                                _align: usize)
-                                                -> usize {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
+                                              old_size: usize,
+                                              old_align: usize,
+                                              new_size: usize,
+                                              new_align: usize,
+                                              excess: *mut usize,
+                                              err: *mut u8) -> *mut u8 {
+        let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
+        if !p.is_null() {
+            *excess = new_size;
+        }
+        return p
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
+                                             old_size: usize,
+                                             old_align: usize,
+                                             new_size: usize,
+                                             new_align: usize) -> u8 {
+        __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
+                                               _old_size: usize,
+                                               old_align: usize,
+                                               new_size: usize,
+                                               new_align: usize) -> u8 {
+        if old_align == new_align {
+            let flags = align_to_flags(new_align);
+            (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8
+        } else {
+            0
+        }
     }
 }
diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml
index 8e3c2c0b9cc66..f20be5fdf5f2b 100644
--- a/src/liballoc_system/Cargo.toml
+++ b/src/liballoc_system/Cargo.toml
@@ -12,3 +12,6 @@ doc = false
 [dependencies]
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
+
+[target.'cfg(not(stage0))'.dependencies]
+alloc = { path = "../liballoc" }
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 1f36bc4fbcea7..afecfc16f2c90 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -11,13 +11,18 @@
 #![crate_name = "alloc_system"]
 #![crate_type = "rlib"]
 #![no_std]
-#![allocator]
 #![deny(warnings)]
 #![unstable(feature = "alloc_system",
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
             issue = "27783")]
-#![feature(allocator)]
+#![cfg_attr(stage0, allocator)]
+#![cfg_attr(stage0, feature(allocator))]
+#![cfg_attr(stage0, feature(core_intrinsics))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(alloc))]
+#![cfg_attr(not(stage0), feature(core_intrinsics))]
 #![feature(staged_api)]
 #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
 
@@ -39,62 +44,201 @@ const MIN_ALIGN: usize = 8;
               target_arch = "sparc64")))]
 const MIN_ALIGN: usize = 16;
 
-#[no_mangle]
-pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
-    unsafe { imp::allocate(size, align) }
-}
+#[cfg(stage0)]
+pub use old::*;
+#[cfg(stage0)]
+mod old;
 
-#[no_mangle]
-pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-    unsafe { imp::allocate_zeroed(size, align) }
-}
+#[cfg(not(stage0))]
+pub use new::System;
+#[cfg(not(stage0))]
+mod new {
+    pub extern crate alloc;
 
-#[no_mangle]
-pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
-    unsafe { imp::deallocate(ptr, old_size, align) }
-}
+    use self::alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace};
 
-#[no_mangle]
-pub extern "C" fn __rust_reallocate(ptr: *mut u8,
-                                    old_size: usize,
-                                    size: usize,
-                                    align: usize)
-                                    -> *mut u8 {
-    unsafe { imp::reallocate(ptr, old_size, size, align) }
-}
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub struct System;
 
-#[no_mangle]
-pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
-                                            old_size: usize,
-                                            size: usize,
-                                            align: usize)
-                                            -> usize {
-    unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
-}
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl Alloc for System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            (&*self).alloc(layout)
+        }
+
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            (&*self).alloc_zeroed(layout)
+        }
+
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+            (&*self).dealloc(ptr, layout)
+        }
+
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            (&*self).realloc(ptr, old_layout, new_layout)
+        }
 
-#[no_mangle]
-pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
-    imp::usable_size(size, align)
+        fn oom(&mut self, err: AllocErr) -> ! {
+            (&*self).oom(err)
+        }
+
+        #[inline]
+        fn usable_size(&self, layout: &Layout) -> (usize, usize) {
+            (&self).usable_size(layout)
+        }
+
+        #[inline]
+        unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+            (&*self).alloc_excess(layout)
+        }
+
+        #[inline]
+        unsafe fn realloc_excess(&mut self,
+                                 ptr: *mut u8,
+                                 layout: Layout,
+                                 new_layout: Layout) -> Result<Excess, AllocErr> {
+            (&*self).realloc_excess(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn grow_in_place(&mut self,
+                                ptr: *mut u8,
+                                layout: Layout,
+                                new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            (&*self).grow_in_place(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn shrink_in_place(&mut self,
+                                  ptr: *mut u8,
+                                  layout: Layout,
+                                  new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            (&*self).shrink_in_place(ptr, layout, new_layout)
+        }
+    }
 }
 
-#[cfg(any(unix, target_os = "redox"))]
-mod imp {
+#[cfg(all(not(stage0), any(unix, target_os = "redox")))]
+mod platform {
     extern crate libc;
 
     use core::cmp;
     use core::ptr;
+
     use MIN_ALIGN;
+    use new::System;
+    use new::alloc::heap::{Alloc, AllocErr, Layout};
+
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl<'a> Alloc for &'a System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            let ptr = if layout.align() <= MIN_ALIGN {
+                libc::malloc(layout.size()) as *mut u8
+            } else {
+                aligned_malloc(&layout)
+            };
+            if !ptr.is_null() {
+                Ok(ptr)
+            } else {
+                Err(AllocErr::Exhausted { request: layout })
+            }
+        }
 
-    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            libc::malloc(size as libc::size_t) as *mut u8
-        } else {
-            aligned_malloc(size, align)
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            if layout.align() <= MIN_ALIGN {
+                let ptr = libc::calloc(layout.size(), 1) as *mut u8;
+                if !ptr.is_null() {
+                    Ok(ptr)
+                } else {
+                    Err(AllocErr::Exhausted { request: layout })
+                }
+            } else {
+                let ret = self.alloc(layout.clone());
+                if let Ok(ptr) = ret {
+                    ptr::write_bytes(ptr, 0, layout.size());
+                }
+                ret
+            }
+        }
+
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) {
+            libc::free(ptr as *mut libc::c_void)
+        }
+
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            if old_layout.align() != new_layout.align() {
+                return Err(AllocErr::Unsupported {
+                    details: "cannot change alignment on `realloc`",
+                })
+            }
+
+            if new_layout.align() <= MIN_ALIGN {
+                let ptr = libc::realloc(ptr as *mut libc::c_void, new_layout.size());
+                if !ptr.is_null() {
+                    Ok(ptr as *mut u8)
+                } else {
+                    Err(AllocErr::Exhausted { request: new_layout })
+                }
+            } else {
+                let res = self.alloc(new_layout.clone());
+                if let Ok(new_ptr) = res {
+                    let size = cmp::min(old_layout.size(), new_layout.size());
+                    ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                    self.dealloc(ptr, old_layout);
+                }
+                res
+            }
+        }
+
+        fn oom(&mut self, err: AllocErr) -> ! {
+            use core::fmt::{self, Write};
+
+            // Print a message to stderr before aborting to assist with
+            // debugging. It is critical that this code does not allocate any
+            // memory since we are in an OOM situation. Any errors are ignored
+            // while printing since there's nothing we can do about them and we
+            // are about to exit anyways.
+            drop(writeln!(Stderr, "fatal runtime error: {}", err));
+            unsafe {
+                ::core::intrinsics::abort();
+            }
+
+            struct Stderr;
+
+            impl Write for Stderr {
+                fn write_str(&mut self, s: &str) -> fmt::Result {
+                    unsafe {
+                        libc::write(libc::STDERR_FILENO,
+                                    s.as_ptr() as *const libc::c_void,
+                                    s.len());
+                    }
+                    Ok(())
+                }
+            }
         }
     }
 
     #[cfg(any(target_os = "android", target_os = "redox"))]
-    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+    #[inline]
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
         // On android we currently target API level 9 which unfortunately
         // doesn't have the `posix_memalign` API used below. Instead we use
         // `memalign`, but this unfortunately has the property on some systems
@@ -112,74 +256,41 @@ mod imp {
         // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
         // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
         //                                       /memory/aligned_memory.cc
-        libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
+        libc::memalign(layout.align(), layout.size()) as *mut u8
     }
 
     #[cfg(not(any(target_os = "android", target_os = "redox")))]
-    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+    #[inline]
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
         let mut out = ptr::null_mut();
-        let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
+        let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
         if ret != 0 {
             ptr::null_mut()
         } else {
             out as *mut u8
         }
     }
-
-    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            libc::calloc(size as libc::size_t, 1) as *mut u8
-        } else {
-            let ptr = aligned_malloc(size, align);
-            if !ptr.is_null() {
-                ptr::write_bytes(ptr, 0, size);
-            }
-            ptr
-        }
-    }
-
-    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
-        } else {
-            let new_ptr = allocate(size, align);
-            if !new_ptr.is_null() {
-                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
-                deallocate(ptr, old_size, align);
-            }
-            new_ptr
-        }
-    }
-
-    pub unsafe fn reallocate_inplace(_ptr: *mut u8,
-                                     old_size: usize,
-                                     _size: usize,
-                                     _align: usize)
-                                     -> usize {
-        old_size
-    }
-
-    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
-        libc::free(ptr as *mut libc::c_void)
-    }
-
-    pub fn usable_size(size: usize, _align: usize) -> usize {
-        size
-    }
 }
 
-#[cfg(windows)]
+#[cfg(all(windows, not(stage0)))]
 #[allow(bad_style)]
-mod imp {
-    use core::cmp::min;
-    use core::ptr::copy_nonoverlapping;
+mod platform {
+    use core::cmp;
+    use core::ptr;
+
     use MIN_ALIGN;
+    use new::System;
+    use new::alloc::heap::{Alloc, AllocErr, Layout, CannotReallocInPlace};
 
     type LPVOID = *mut u8;
     type HANDLE = LPVOID;
     type SIZE_T = usize;
     type DWORD = u32;
     type BOOL = i32;
+    type LPDWORD = *mut DWORD;
+    type LPOVERLAPPED = *mut u8;
+
+    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
 
     extern "system" {
         fn GetProcessHeap() -> HANDLE;
@@ -187,12 +298,18 @@ mod imp {
         fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
         fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
         fn GetLastError() -> DWORD;
+        fn WriteFile(hFile: HANDLE,
+                     lpBuffer: LPVOID,
+                     nNumberOfBytesToWrite: DWORD,
+                     lpNumberOfBytesWritten: LPDWORD,
+                     lpOverlapped: LPOVERLAPPED)
+                     -> BOOL;
+        fn GetStdHandle(which: DWORD) -> HANDLE;
     }
 
     #[repr(C)]
     struct Header(*mut u8);
 
-
     const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
     const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;
 
@@ -207,71 +324,149 @@ mod imp {
     }
 
     #[inline]
-    unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8
+    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD)
+        -> Result<*mut u8, AllocErr>
+    {
+        let ptr = if layout.align() <= MIN_ALIGN {
+            HeapAlloc(GetProcessHeap(), flags, layout.size())
         } else {
-            let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8;
+            let size = layout.size() + layout.align();
+            let ptr = HeapAlloc(GetProcessHeap(), flags, size);
             if ptr.is_null() {
-                return ptr;
+                ptr
+            } else {
+                align_ptr(ptr, layout.align())
             }
-            align_ptr(ptr, align)
+        };
+        if ptr.is_null() {
+            Err(AllocErr::Exhausted { request: layout })
+        } else {
+            Ok(ptr as *mut u8)
         }
     }
 
-    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-        allocate_with_flags(size, align, 0)
-    }
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl<'a> Alloc for &'a System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            allocate_with_flags(layout, 0)
+        }
 
-    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-        allocate_with_flags(size, align, HEAP_ZERO_MEMORY)
-    }
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
+        }
 
-    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
-        } else {
-            let new = allocate(size, align);
-            if !new.is_null() {
-                copy_nonoverlapping(ptr, new, min(size, old_size));
-                deallocate(ptr, old_size, align);
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+            if layout.align() <= MIN_ALIGN {
+                let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
+            } else {
+                let header = get_header(ptr);
+                let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
             }
-            new
         }
-    }
 
-    pub unsafe fn reallocate_inplace(ptr: *mut u8,
-                                     old_size: usize,
-                                     size: usize,
-                                     align: usize)
-                                     -> usize {
-        let new = if align <= MIN_ALIGN {
-            HeapReAlloc(GetProcessHeap(),
-                        HEAP_REALLOC_IN_PLACE_ONLY,
-                        ptr as LPVOID,
-                        size as SIZE_T) as *mut u8
-        } else {
-            let header = get_header(ptr);
-            HeapReAlloc(GetProcessHeap(),
-                        HEAP_REALLOC_IN_PLACE_ONLY,
-                        header.0 as LPVOID,
-                        size + align as SIZE_T) as *mut u8
-        };
-        if new.is_null() { old_size } else { size }
-    }
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            if old_layout.align() != new_layout.align() {
+                return Err(AllocErr::Unsupported {
+                    details: "cannot change alignment on `realloc`",
+                })
+            }
 
-    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
-        if align <= MIN_ALIGN {
-            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
-        } else {
-            let header = get_header(ptr);
-            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
+            if new_layout.align() <= MIN_ALIGN {
+                let ptr = HeapReAlloc(GetProcessHeap(),
+                                      0,
+                                      ptr as LPVOID,
+                                      new_layout.size());
+                if !ptr.is_null() {
+                    Ok(ptr as *mut u8)
+                } else {
+                    Err(AllocErr::Exhausted { request: new_layout })
+                }
+            } else {
+                let res = self.alloc(new_layout.clone());
+                if let Ok(new_ptr) = res {
+                    let size = cmp::min(old_layout.size(), new_layout.size());
+                    ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                    self.dealloc(ptr, old_layout);
+                }
+                res
+            }
         }
-    }
 
-    pub fn usable_size(size: usize, _align: usize) -> usize {
-        size
+        #[inline]
+        unsafe fn grow_in_place(&mut self,
+                                ptr: *mut u8,
+                                layout: Layout,
+                                new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            self.shrink_in_place(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn shrink_in_place(&mut self,
+                                  ptr: *mut u8,
+                                  old_layout: Layout,
+                                  new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            if old_layout.align() != new_layout.align() {
+                return Err(CannotReallocInPlace)
+            }
+
+            let new = if new_layout.align() <= MIN_ALIGN {
+                HeapReAlloc(GetProcessHeap(),
+                            HEAP_REALLOC_IN_PLACE_ONLY,
+                            ptr as LPVOID,
+                            new_layout.size())
+            } else {
+                let header = get_header(ptr);
+                HeapReAlloc(GetProcessHeap(),
+                            HEAP_REALLOC_IN_PLACE_ONLY,
+                            header.0 as LPVOID,
+                            new_layout.size() + new_layout.align())
+            };
+            if new.is_null() {
+                Err(CannotReallocInPlace)
+            } else {
+                Ok(())
+            }
+        }
+
+        fn oom(&mut self, err: AllocErr) -> ! {
+            use core::fmt::{self, Write};
+
+            // Same as with unix we ignore all errors here
+            drop(writeln!(Stderr, "fatal runtime error: {}", err));
+            unsafe {
+                ::core::intrinsics::abort();
+            }
+
+            struct Stderr;
+
+            impl Write for Stderr {
+                fn write_str(&mut self, s: &str) -> fmt::Result {
+                    unsafe {
+                        // WriteFile silently fails if it is passed an invalid
+                        // handle, so there is no need to check the result of
+                        // GetStdHandle.
+                        WriteFile(GetStdHandle(STD_ERROR_HANDLE),
+                                  s.as_ptr() as LPVOID,
+                                  s.len() as DWORD,
+                                  ptr::null_mut(),
+                                  ptr::null_mut());
+                    }
+                    Ok(())
+                }
+            }
+        }
     }
 }
diff --git a/src/liballoc_system/old.rs b/src/liballoc_system/old.rs
new file mode 100644
index 0000000000000..80aa46075944c
--- /dev/null
+++ b/src/liballoc_system/old.rs
@@ -0,0 +1,268 @@
+// 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.
+
+#[no_mangle]
+pub unsafe extern fn __rust_alloc(size: usize,
+                                  align: usize,
+                                  err: *mut u8) -> *mut u8 {
+    let p = imp::allocate(size, align);
+    if p.is_null() {
+        __rust_oom(err);
+    }
+    p
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_oom(_err: *const u8) -> ! {
+    ::core::intrinsics::abort()
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_dealloc(ptr: *mut u8,
+                                    size: usize,
+                                    align: usize) {
+    imp::deallocate(ptr, size, align)
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_usable_size(size: usize,
+                                        _align: usize,
+                                        min: *mut usize,
+                                        max: *mut usize) {
+    *min = size;
+    *max = size;
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_realloc(ptr: *mut u8,
+                                    old_size: usize,
+                                    old_align: usize,
+                                    new_size: usize,
+                                    new_align: usize,
+                                    err: *mut u8) -> *mut u8 {
+    if new_align != old_align {
+        __rust_oom(err);
+    }
+    let p = imp::reallocate(ptr, old_size, new_size, new_align);
+    if p.is_null() {
+        __rust_oom(err);
+    }
+    p
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_alloc_zeroed(size: usize,
+                                         align: usize,
+                                         err: *mut u8) -> *mut u8 {
+    let p = imp::allocate_zeroed(size, align);
+    if p.is_null() {
+        __rust_oom(err);
+    }
+    p
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_alloc_excess(_size: usize,
+                                         _align: usize,
+                                         _excess: *mut usize,
+                                         err: *mut u8) -> *mut u8 {
+    __rust_oom(err);
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_realloc_excess(_ptr: *mut u8,
+                                           _old_size: usize,
+                                           _old_align: usize,
+                                           _new_size: usize,
+                                           _new_align: usize,
+                                           _excess: *mut usize,
+                                           err: *mut u8) -> *mut u8 {
+    __rust_oom(err);
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_grow_in_place(_ptr: *mut u8,
+                                          _old_size: usize,
+                                          _old_align: usize,
+                                          _new_size: usize,
+                                          _new_align: usize) -> u8 {
+    0
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_shrink_in_place(_ptr: *mut u8,
+                                            _old_size: usize,
+                                            _old_align: usize,
+                                            _new_size: usize,
+                                            _new_align: usize) -> u8 {
+    0
+}
+
+#[cfg(any(unix, target_os = "redox"))]
+mod imp {
+    extern crate libc;
+
+    use core::cmp;
+    use core::ptr;
+    use MIN_ALIGN;
+
+    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            libc::malloc(size as libc::size_t) as *mut u8
+        } else {
+            aligned_malloc(size, align)
+        }
+    }
+
+    #[cfg(any(target_os = "android", target_os = "redox"))]
+    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+        // On android we currently target API level 9 which unfortunately
+        // doesn't have the `posix_memalign` API used below. Instead we use
+        // `memalign`, but this unfortunately has the property on some systems
+        // where the memory returned cannot be deallocated by `free`!
+        //
+        // Upon closer inspection, however, this appears to work just fine with
+        // Android, so for this platform we should be fine to call `memalign`
+        // (which is present in API level 9). Some helpful references could
+        // possibly be chromium using memalign [1], attempts at documenting that
+        // memalign + free is ok [2] [3], or the current source of chromium
+        // which still uses memalign on android [4].
+        //
+        // [1]: https://codereview.chromium.org/10796020/
+        // [2]: https://code.google.com/p/android/issues/detail?id=35391
+        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+        //                                       /memory/aligned_memory.cc
+        libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
+    }
+
+    #[cfg(not(any(target_os = "android", target_os = "redox")))]
+    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+        let mut out = ptr::null_mut();
+        let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
+        if ret != 0 {
+            ptr::null_mut()
+        } else {
+            out as *mut u8
+        }
+    }
+
+    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            libc::calloc(size as libc::size_t, 1) as *mut u8
+        } else {
+            let ptr = aligned_malloc(size, align);
+            if !ptr.is_null() {
+                ptr::write_bytes(ptr, 0, size);
+            }
+            ptr
+        }
+    }
+
+    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
+        } else {
+            let new_ptr = allocate(size, align);
+            if !new_ptr.is_null() {
+                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
+                deallocate(ptr, old_size, align);
+            }
+            new_ptr
+        }
+    }
+
+    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
+        libc::free(ptr as *mut libc::c_void)
+    }
+}
+
+#[cfg(windows)]
+#[allow(bad_style)]
+mod imp {
+    use core::cmp::min;
+    use core::ptr::copy_nonoverlapping;
+    use MIN_ALIGN;
+
+    type LPVOID = *mut u8;
+    type HANDLE = LPVOID;
+    type SIZE_T = usize;
+    type DWORD = u32;
+    type BOOL = i32;
+
+    extern "system" {
+        fn GetProcessHeap() -> HANDLE;
+        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+        fn GetLastError() -> DWORD;
+    }
+
+    #[repr(C)]
+    struct Header(*mut u8);
+
+
+    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+
+    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+        &mut *(ptr as *mut Header).offset(-1)
+    }
+
+    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+        let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
+        *get_header(aligned) = Header(ptr);
+        aligned
+    }
+
+    #[inline]
+    unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8
+        } else {
+            let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8;
+            if ptr.is_null() {
+                return ptr;
+            }
+            align_ptr(ptr, align)
+        }
+    }
+
+    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
+        allocate_with_flags(size, align, 0)
+    }
+
+    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
+        allocate_with_flags(size, align, HEAP_ZERO_MEMORY)
+    }
+
+    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
+        } else {
+            let new = allocate(size, align);
+            if !new.is_null() {
+                copy_nonoverlapping(ptr, new, min(size, old_size));
+                deallocate(ptr, old_size, align);
+            }
+            new
+        }
+    }
+
+    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
+        if align <= MIN_ALIGN {
+            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
+        } else {
+            let header = get_header(ptr);
+            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
+        }
+    }
+}
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index de5d6df328cbd..38143593eb12b 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -23,13 +23,11 @@
        issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
        test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
 #![no_std]
-#![needs_allocator]
 #![deny(warnings)]
 
 #![feature(alloc)]
 #![feature(collections_range)]
 #![feature(macro_reexport)]
-#![feature(needs_allocator)]
 #![feature(staged_api)]
 
 //! Collection types
diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins
new file mode 160000
index 0000000000000..238647af80647
--- /dev/null
+++ b/src/libcompiler_builtins
@@ -0,0 +1 @@
+Subproject commit 238647af806470dc73e585c03682083931d29cd5
diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml
deleted file mode 100644
index 2c9cee5e7a093..0000000000000
--- a/src/libcompiler_builtins/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-build = "build.rs"
-name = "compiler_builtins"
-version = "0.0.0"
-
-[lib]
-name = "compiler_builtins"
-path = "lib.rs"
-test = false
-bench = false
-doc = false
-
-[dependencies]
-core = { path = "../libcore" }
-
-[build-dependencies]
-build_helper = { path = "../build_helper" }
-gcc = "0.3.50"
diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs
deleted file mode 100644
index 8fe79057bd817..0000000000000
--- a/src/libcompiler_builtins/build.rs
+++ /dev/null
@@ -1,423 +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.
-
-//! Compiles the `compiler-rt` library, or at least the builtins part of it.
-//!
-//! Note that while compiler-rt has a build system associated with it, we
-//! specifically don't use it here. The compiler-rt build system, written in
-//! CMake, is actually *very* difficult to work with in terms of getting it to
-//! compile on all the relevant platforms we want it to compile on. In the end
-//! it became so much pain to work with local patches, work around the oddities
-//! of the build system, etc, that we're just building everything by hand now.
-//!
-//! In general compiler-rt is just a bunch of intrinsics that are in practice
-//! *very* stable. We just need to make sure that all the relevant functions and
-//! such are compiled somewhere and placed in an object file somewhere.
-//! Eventually, these should all be written in Rust!
-//!
-//! So below you'll find a listing of every single file in the compiler-rt repo
-//! that we're compiling. We just reach in and compile with the `gcc` crate
-//! which should have all the relevant flags and such already configured.
-//!
-//! The risk here is that if we update compiler-rt we may need to compile some
-//! new intrinsics, but to be honest we surely don't use all of the intrinsics
-//! listed below today so the likelihood of us actually needing a new intrinsic
-//! is quite low. The failure case is also just that someone reports a link
-//! error (if any) and then we just add it to the list. Overall, that cost is
-//! far far less than working with compiler-rt's build system over time.
-
-extern crate build_helper;
-extern crate gcc;
-
-use std::collections::BTreeMap;
-use std::env;
-use std::path::Path;
-use build_helper::native_lib_boilerplate;
-
-struct Sources {
-    // SYMBOL -> PATH TO SOURCE
-    map: BTreeMap<&'static str, &'static str>,
-}
-
-impl Sources {
-    fn new() -> Sources {
-        Sources { map: BTreeMap::new() }
-    }
-
-    fn extend(&mut self, sources: &[&'static str]) {
-        // NOTE Some intrinsics have both a generic implementation (e.g.
-        // `floatdidf.c`) and an arch optimized implementation
-        // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized
-        // implementation and discard the generic implementation. If we don't
-        // and keep both implementations, the linker will yell at us about
-        // duplicate symbols!
-        for &src in sources {
-            let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap();
-            if src.contains("/") {
-                // Arch-optimized implementation (preferred)
-                self.map.insert(symbol, src);
-            } else {
-                // Generic implementation
-                if !self.map.contains_key(symbol) {
-                    self.map.insert(symbol, src);
-                }
-            }
-        }
-    }
-}
-
-fn main() {
-    let target = env::var("TARGET").expect("TARGET was not set");
-
-    // Emscripten's runtime includes all the builtins
-    if target.contains("emscripten") {
-        return;
-    }
-
-    // Can't reuse `sources` list for the freshness check becuse it doesn't contain header files.
-    let native = match native_lib_boilerplate("compiler-rt", "compiler-rt", "compiler-rt", ".") {
-        Ok(native) => native,
-        _ => return,
-    };
-
-    let cfg = &mut gcc::Config::new();
-    cfg.out_dir(&native.out_dir);
-
-    if target.contains("msvc") {
-        // Don't pull in extra libraries on MSVC
-        cfg.flag("/Zl");
-
-        // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
-        cfg.define("__func__", Some("__FUNCTION__"));
-    } else {
-        // Turn off various features of gcc and such, mostly copying
-        // compiler-rt's build system already
-        cfg.flag("-fno-builtin");
-        cfg.flag("-fvisibility=hidden");
-        // Accepted practice on Solaris is to never omit frame pointer so that
-        // system observability tools work as expected.  In addition, at least
-        // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate
-        // references to data outside of the current stack frame.  A search of
-        // the gcc bug database provides a variety of issues surrounding
-        // -fomit-frame-pointer on non-x86 platforms.
-        if !target.contains("solaris") && !target.contains("sparc") {
-            cfg.flag("-fomit-frame-pointer");
-        }
-        cfg.flag("-ffreestanding");
-        cfg.define("VISIBILITY_HIDDEN", None);
-    }
-
-    let mut sources = Sources::new();
-    sources.extend(&["absvdi2.c",
-                     "absvsi2.c",
-                     "adddf3.c",
-                     "addsf3.c",
-                     "addvdi3.c",
-                     "addvsi3.c",
-                     "apple_versioning.c",
-                     "ashldi3.c",
-                     "ashrdi3.c",
-                     "clzdi2.c",
-                     "clzsi2.c",
-                     "cmpdi2.c",
-                     "comparedf2.c",
-                     "comparesf2.c",
-                     "ctzdi2.c",
-                     "ctzsi2.c",
-                     "divdc3.c",
-                     "divdf3.c",
-                     "divdi3.c",
-                     "divmoddi4.c",
-                     "divmodsi4.c",
-                     "divsc3.c",
-                     "divsf3.c",
-                     "divsi3.c",
-                     "divxc3.c",
-                     "extendsfdf2.c",
-                     "extendhfsf2.c",
-                     "ffsdi2.c",
-                     "fixdfdi.c",
-                     "fixdfsi.c",
-                     "fixsfdi.c",
-                     "fixsfsi.c",
-                     "fixunsdfdi.c",
-                     "fixunsdfsi.c",
-                     "fixunssfdi.c",
-                     "fixunssfsi.c",
-                     "fixunsxfdi.c",
-                     "fixunsxfsi.c",
-                     "fixxfdi.c",
-                     "floatdidf.c",
-                     "floatdisf.c",
-                     "floatdixf.c",
-                     "floatsidf.c",
-                     "floatsisf.c",
-                     "floatundidf.c",
-                     "floatundisf.c",
-                     "floatundixf.c",
-                     "floatunsidf.c",
-                     "floatunsisf.c",
-                     "int_util.c",
-                     "lshrdi3.c",
-                     "moddi3.c",
-                     "modsi3.c",
-                     "muldc3.c",
-                     "muldf3.c",
-                     "muldi3.c",
-                     "mulodi4.c",
-                     "mulosi4.c",
-                     "muloti4.c",
-                     "mulsc3.c",
-                     "mulsf3.c",
-                     "mulvdi3.c",
-                     "mulvsi3.c",
-                     "mulxc3.c",
-                     "negdf2.c",
-                     "negdi2.c",
-                     "negsf2.c",
-                     "negvdi2.c",
-                     "negvsi2.c",
-                     "paritydi2.c",
-                     "paritysi2.c",
-                     "popcountdi2.c",
-                     "popcountsi2.c",
-                     "powidf2.c",
-                     "powisf2.c",
-                     "powixf2.c",
-                     "subdf3.c",
-                     "subsf3.c",
-                     "subvdi3.c",
-                     "subvsi3.c",
-                     "truncdfhf2.c",
-                     "truncdfsf2.c",
-                     "truncsfhf2.c",
-                     "ucmpdi2.c",
-                     "udivdi3.c",
-                     "udivmoddi4.c",
-                     "udivmodsi4.c",
-                     "udivsi3.c",
-                     "umoddi3.c",
-                     "umodsi3.c"]);
-
-    if !target.contains("ios") {
-        sources.extend(&["absvti2.c",
-                         "addvti3.c",
-                         "ashlti3.c",
-                         "ashrti3.c",
-                         "clzti2.c",
-                         "cmpti2.c",
-                         "ctzti2.c",
-                         "divti3.c",
-                         "ffsti2.c",
-                         "fixdfti.c",
-                         "fixsfti.c",
-                         "fixunsdfti.c",
-                         "fixunssfti.c",
-                         "fixunsxfti.c",
-                         "fixxfti.c",
-                         "floattidf.c",
-                         "floattisf.c",
-                         "floattixf.c",
-                         "floatuntidf.c",
-                         "floatuntisf.c",
-                         "floatuntixf.c",
-                         "lshrti3.c",
-                         "modti3.c",
-                         "multi3.c",
-                         "mulvti3.c",
-                         "negti2.c",
-                         "negvti2.c",
-                         "parityti2.c",
-                         "popcountti2.c",
-                         "subvti3.c",
-                         "ucmpti2.c",
-                         "udivmodti4.c",
-                         "udivti3.c",
-                         "umodti3.c"]);
-    }
-
-    if target.contains("apple") {
-        sources.extend(&["atomic_flag_clear.c",
-                         "atomic_flag_clear_explicit.c",
-                         "atomic_flag_test_and_set.c",
-                         "atomic_flag_test_and_set_explicit.c",
-                         "atomic_signal_fence.c",
-                         "atomic_thread_fence.c"]);
-    }
-
-    if target.contains("msvc") {
-        if target.contains("x86_64") {
-            sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
-        }
-    } else {
-        if !target.contains("freebsd") && !target.contains("netbsd") {
-            sources.extend(&["gcc_personality_v0.c"]);
-        }
-
-        if target.contains("x86_64") {
-            sources.extend(&["x86_64/chkstk.S",
-                             "x86_64/chkstk2.S",
-                             "x86_64/floatdidf.c",
-                             "x86_64/floatdisf.c",
-                             "x86_64/floatdixf.c",
-                             "x86_64/floatundidf.S",
-                             "x86_64/floatundisf.S",
-                             "x86_64/floatundixf.S"]);
-        }
-
-        if target.contains("i386") || target.contains("i586") || target.contains("i686") {
-            sources.extend(&["i386/ashldi3.S",
-                             "i386/ashrdi3.S",
-                             "i386/chkstk.S",
-                             "i386/chkstk2.S",
-                             "i386/divdi3.S",
-                             "i386/floatdidf.S",
-                             "i386/floatdisf.S",
-                             "i386/floatdixf.S",
-                             "i386/floatundidf.S",
-                             "i386/floatundisf.S",
-                             "i386/floatundixf.S",
-                             "i386/lshrdi3.S",
-                             "i386/moddi3.S",
-                             "i386/muldi3.S",
-                             "i386/udivdi3.S",
-                             "i386/umoddi3.S"]);
-        }
-    }
-
-    if target.contains("arm") && !target.contains("ios") {
-        // (At least) udivsi3.S is broken for Thumb 1 which our gcc uses by
-        // default, we don't want Thumb 2 since it isn't supported on some
-        // devices, so disable thumb entirely.
-        // Upstream bug: https://bugs.llvm.org/show_bug.cgi?id=32492
-        cfg.define("__ARM_ARCH_ISA_THUMB", Some("0"));
-
-        sources.extend(&["arm/aeabi_cdcmp.S",
-                         "arm/aeabi_cdcmpeq_check_nan.c",
-                         "arm/aeabi_cfcmp.S",
-                         "arm/aeabi_cfcmpeq_check_nan.c",
-                         "arm/aeabi_dcmp.S",
-                         "arm/aeabi_div0.c",
-                         "arm/aeabi_drsub.c",
-                         "arm/aeabi_fcmp.S",
-                         "arm/aeabi_frsub.c",
-                         "arm/aeabi_idivmod.S",
-                         "arm/aeabi_ldivmod.S",
-                         "arm/aeabi_memcmp.S",
-                         "arm/aeabi_memcpy.S",
-                         "arm/aeabi_memmove.S",
-                         "arm/aeabi_memset.S",
-                         "arm/aeabi_uidivmod.S",
-                         "arm/aeabi_uldivmod.S",
-                         "arm/bswapdi2.S",
-                         "arm/bswapsi2.S",
-                         "arm/clzdi2.S",
-                         "arm/clzsi2.S",
-                         "arm/comparesf2.S",
-                         "arm/divmodsi4.S",
-                         "arm/divsi3.S",
-                         "arm/modsi3.S",
-                         "arm/switch16.S",
-                         "arm/switch32.S",
-                         "arm/switch8.S",
-                         "arm/switchu8.S",
-                         "arm/sync_synchronize.S",
-                         "arm/udivmodsi4.S",
-                         "arm/udivsi3.S",
-                         "arm/umodsi3.S"]);
-    }
-
-    if target.contains("armv7") {
-        sources.extend(&["arm/sync_fetch_and_add_4.S",
-                         "arm/sync_fetch_and_add_8.S",
-                         "arm/sync_fetch_and_and_4.S",
-                         "arm/sync_fetch_and_and_8.S",
-                         "arm/sync_fetch_and_max_4.S",
-                         "arm/sync_fetch_and_max_8.S",
-                         "arm/sync_fetch_and_min_4.S",
-                         "arm/sync_fetch_and_min_8.S",
-                         "arm/sync_fetch_and_nand_4.S",
-                         "arm/sync_fetch_and_nand_8.S",
-                         "arm/sync_fetch_and_or_4.S",
-                         "arm/sync_fetch_and_or_8.S",
-                         "arm/sync_fetch_and_sub_4.S",
-                         "arm/sync_fetch_and_sub_8.S",
-                         "arm/sync_fetch_and_umax_4.S",
-                         "arm/sync_fetch_and_umax_8.S",
-                         "arm/sync_fetch_and_umin_4.S",
-                         "arm/sync_fetch_and_umin_8.S",
-                         "arm/sync_fetch_and_xor_4.S",
-                         "arm/sync_fetch_and_xor_8.S"]);
-    }
-
-    if target.contains("eabihf") {
-        sources.extend(&["arm/adddf3vfp.S",
-                         "arm/addsf3vfp.S",
-                         "arm/divdf3vfp.S",
-                         "arm/divsf3vfp.S",
-                         "arm/eqdf2vfp.S",
-                         "arm/eqsf2vfp.S",
-                         "arm/extendsfdf2vfp.S",
-                         "arm/fixdfsivfp.S",
-                         "arm/fixsfsivfp.S",
-                         "arm/fixunsdfsivfp.S",
-                         "arm/fixunssfsivfp.S",
-                         "arm/floatsidfvfp.S",
-                         "arm/floatsisfvfp.S",
-                         "arm/floatunssidfvfp.S",
-                         "arm/floatunssisfvfp.S",
-                         "arm/gedf2vfp.S",
-                         "arm/gesf2vfp.S",
-                         "arm/gtdf2vfp.S",
-                         "arm/gtsf2vfp.S",
-                         "arm/ledf2vfp.S",
-                         "arm/lesf2vfp.S",
-                         "arm/ltdf2vfp.S",
-                         "arm/ltsf2vfp.S",
-                         "arm/muldf3vfp.S",
-                         "arm/mulsf3vfp.S",
-                         "arm/negdf2vfp.S",
-                         "arm/negsf2vfp.S",
-                         "arm/nedf2vfp.S",
-                         "arm/nesf2vfp.S",
-                         "arm/restore_vfp_d8_d15_regs.S",
-                         "arm/save_vfp_d8_d15_regs.S",
-                         "arm/subdf3vfp.S",
-                         "arm/subsf3vfp.S",
-                         "arm/truncdfsf2vfp.S",
-                         "arm/unorddf2vfp.S",
-                         "arm/unordsf2vfp.S"]);
-    }
-
-    if target.contains("aarch64") {
-        sources.extend(&["comparetf2.c",
-                         "extenddftf2.c",
-                         "extendsftf2.c",
-                         "fixtfdi.c",
-                         "fixtfsi.c",
-                         "fixtfti.c",
-                         "fixunstfdi.c",
-                         "fixunstfsi.c",
-                         "fixunstfti.c",
-                         "floatditf.c",
-                         "floatsitf.c",
-                         "floatunditf.c",
-                         "floatunsitf.c",
-                         "multc3.c",
-                         "trunctfdf2.c",
-                         "trunctfsf2.c"]);
-    }
-
-    for src in sources.map.values() {
-        cfg.file(Path::new("../compiler-rt/lib/builtins").join(src));
-    }
-
-    cfg.compile("libcompiler-rt.a");
-}
diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs
deleted file mode 100644
index 09b3d63950705..0000000000000
--- a/src/libcompiler_builtins/lib.rs
+++ /dev/null
@@ -1,721 +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.
-
-#![feature(compiler_builtins)]
-#![no_std]
-#![compiler_builtins]
-#![unstable(feature = "compiler_builtins_lib",
-            reason = "internal implementation detail of rustc right now",
-            issue = "0")]
-#![crate_name = "compiler_builtins"]
-#![crate_type = "rlib"]
-#![allow(unused_features)]
-#![feature(staged_api, core_intrinsics, repr_simd,
-           i128_type, core_float, abi_unadjusted, associated_consts)]
-#![allow(non_camel_case_types, unused_variables, unused_imports)]
-
-#[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows",
-          target_arch="mips64"))]
-pub mod reimpls {
-
-    #![allow(unused_comparisons)]
-
-    use core::intrinsics::unchecked_div;
-    use core::intrinsics::unchecked_rem;
-    use core::ptr;
-
-    macro_rules! ashl {
-        ($a:expr, $b:expr, $ty:ty) => {{
-            let (a, b) = ($a, $b);
-            let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
-            let half_bits = bits.wrapping_shr(1);
-            if b & half_bits != 0 {
-                <$ty>::from_parts(0, a.low().wrapping_shl(
-                                        b.wrapping_sub(half_bits) as u32))
-            } else if b == 0 {
-                a
-            } else {
-                <$ty>::from_parts(a.low().wrapping_shl(b as u32),
-                                  a.high().wrapping_shl(b as u32)
-                                  | a.low()
-                                     .wrapping_shr(half_bits.wrapping_sub(b) as u32))
-            }
-        }}
-    }
-
-    #[export_name="__ashlti3"]
-    pub extern "C" fn shl(a: u128, b: u128) -> u128 {
-        ashl!(a, b, u128)
-    }
-
-    macro_rules! ashr {
-        ($a: expr, $b: expr, $ty:ty) => {{
-            let (a, b) = ($a, $b);
-            let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
-            let half_bits = bits.wrapping_shr(1);
-            if b & half_bits != 0 {
-                <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32)
-                                  as <$ty as LargeInt>::LowHalf,
-                                  a.high().wrapping_shr(half_bits.wrapping_sub(1) as u32))
-            } else if b == 0 {
-                a
-            } else {
-                let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf;
-                <$ty>::from_parts(high_unsigned.wrapping_shl(half_bits.wrapping_sub(b) as u32)
-                                  | a.low().wrapping_shr(b as u32),
-                                  a.high().wrapping_shr(b as u32))
-            }
-        }}
-    }
-
-    #[export_name="__ashrti3"]
-    pub extern "C" fn shr(a: i128, b: i128) -> i128 {
-        ashr!(a, b, i128)
-    }
-
-    macro_rules! lshr {
-        ($a: expr, $b: expr, $ty:ty) => {{
-            let (a, b) = ($a, $b);
-            let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
-            let half_bits = bits.wrapping_shr(1);
-            if b & half_bits != 0 {
-                <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0)
-            } else if b == 0 {
-                a
-            } else {
-                <$ty>::from_parts(a.high().wrapping_shl(half_bits.wrapping_sub(b) as u32)
-                                  | a.low().wrapping_shr(b as u32),
-                                  a.high().wrapping_shr(b as u32))
-            }
-        }}
-    }
-
-
-    #[export_name="__lshrti3"]
-    pub extern "C" fn lshr(a: u128, b: u128) -> u128 {
-        lshr!(a, b, u128)
-    }
-
-    pub extern "C" fn u128_div_mod(n: u128, d: u128, rem: *mut u128) -> u128 {
-        // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
-        unsafe {
-        // special cases, X is unknown, K != 0
-        if n.high() == 0 {
-            if d.high() == 0 {
-                // 0 X
-                // ---
-                // 0 X
-                if !rem.is_null() {
-                    *rem = u128::from(unchecked_rem(n.low(), d.low()));
-                }
-                return u128::from(unchecked_div(n.low(), d.low()));
-            } else {
-                // 0 X
-                // ---
-                // K X
-                if !rem.is_null() {
-                    *rem = n;
-                }
-                return 0;
-            };
-        }
-
-        let mut sr;
-        let mut q;
-        let mut r;
-
-        if d.low() == 0 {
-            if d.high() == 0 {
-                // K X
-                // ---
-                // 0 0
-                if !rem.is_null() {
-                    *rem = u128::from(unchecked_rem(n.high(), d.low()));
-                }
-                return u128::from(unchecked_div(n.high(), d.low()));
-            }
-
-            if n.low() == 0 {
-                // K 0
-                // ---
-                // K 0
-                if !rem.is_null() {
-                    *rem = u128::from_parts(0, unchecked_rem(n.high(), d.high()));
-                }
-                return u128::from(unchecked_div(n.high(), d.high()));
-            }
-
-            // K K
-            // ---
-            // K 0
-
-            if d.high().is_power_of_two() {
-                if !rem.is_null() {
-                    *rem = u128::from_parts(n.low(),
-                                            n.high() & (d.high().wrapping_sub(1)));
-                }
-                return u128::from(n.high().wrapping_shr(d.high().trailing_zeros()));
-            }
-
-            // K K
-            // ---
-            // K 0
-            sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
-
-            // D > N
-            if sr > 64 - 2 {
-                if !rem.is_null() {
-                    *rem = n;
-                }
-                return 0;
-            }
-
-            sr = sr.wrapping_add(1);
-
-            // 1 <= sr <= u64::bits() - 1
-            q = n.wrapping_shl(128u32.wrapping_sub(sr));
-            r = n.wrapping_shr(sr);
-        } else {
-            if d.high() == 0 {
-                // K X
-                // ---
-                // 0 K
-                if d.low().is_power_of_two() {
-                    if !rem.is_null() {
-                        *rem = u128::from(n.low() & (d.low().wrapping_sub(1)));
-                    }
-
-                    if d.low() == 1 {
-                        return n;
-                    } else {
-                        let sr = d.low().trailing_zeros();
-                        return n.wrapping_shr(sr);
-                    };
-                }
-
-                sr = (1 + 64u32)
-                    .wrapping_add(d.low().leading_zeros())
-                    .wrapping_sub(n.high().leading_zeros());
-
-                // 2 <= sr <= u64::bits() - 1
-                q = n.wrapping_shl(128u32.wrapping_sub(sr));
-                r = n.wrapping_shr(sr);
-                // FIXME the C compiler-rt implementation has something here
-                // that looks like a speed optimisation.
-                // It would be worth a try to port it to Rust too and
-                // compare the speed.
-            } else {
-                // K X
-                // ---
-                // K K
-                sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
-
-                // D > N
-                if sr > 64 - 1 {
-                    if !rem.is_null() {
-                        *rem = n;
-                    }
-                    return 0;
-                }
-
-                sr = sr.wrapping_add(1);
-
-                // 1 <= sr <= u32::bits()
-                q = n.wrapping_shl(128u32.wrapping_sub(sr));
-                r = n.wrapping_shr(sr);
-            }
-        }
-
-        // Not a special case
-        // q and r are initialized with
-        // q = n << (u64::bits() - sr)
-        // r = n >> sr
-        // 1 <= sr <= u64::bits() - 1
-        let mut carry = 0;
-
-        // FIXME: replace this with a for loop
-        // (atm not doable as this generates call to
-        // eh_personality when optimisations are turned off,
-        // which in turn gives a linker error in later
-        // compilation steps)
-        while sr > 0 {
-            // r:q = ((r:q) << 1) | carry
-            r = r.wrapping_shl(1) | q.wrapping_shr(128 - 1);
-            q = q.wrapping_shl(1) | carry as u128;
-
-            // carry = 0
-            // if r >= d {
-            //     r -= d;
-            //     carry = 1;
-            // }
-            let s = ((d.wrapping_sub(r).wrapping_sub(1)) as i128).wrapping_shr(128 - 1);
-            carry = (s & 1) as u64;
-            r = r.wrapping_sub(d & s as u128);
-            sr = sr.wrapping_sub(1);
-        }
-
-        if !rem.is_null() {
-            *rem = r;
-        }
-        (q.wrapping_shl(1)) | carry as u128
-        }
-    }
-
-    fn i128_mod(a: i128, b: i128) -> i128 {
-        let b = b.uabs();
-        let sa = a.signum();
-        let a = a.uabs();
-        unsafe {
-            let mut r = ::core::mem::zeroed();
-            u128_div_mod(a, b, &mut r);
-            if sa == -1 { (r as i128).unchecked_neg() } else { r as i128 }
-        }
-    }
-
-    fn i128_div(a: i128, b: i128) -> i128 {
-        let sa = a.signum();
-        let sb = b.signum();
-        let a = a.uabs();
-        let b = b.uabs();
-        let sr = sa.wrapping_mul(sb); // sign of quotient
-        (if sr == -1 {
-            (u128_div_mod(a, b, ptr::null_mut()) as i128).unchecked_neg()
-        } else {
-            u128_div_mod(a, b, ptr::null_mut()) as i128
-        })
-    }
-
-    macro_rules! mulo {
-        ($a:expr, $b:expr, $o: expr, $ty: ty) => {{
-            let (a, b, overflow) = ($a, $b, $o);
-            *overflow = 0;
-            let result = a.wrapping_mul(b);
-            if a == <$ty>::min_value() {
-                if b != 0 && b != 1 {
-                    *overflow = 1;
-                }
-                return result;
-            }
-            if b == <$ty>::min_value() {
-                if a != 0 && a != 1 {
-                    *overflow = 1;
-                }
-                return result;
-            }
-
-            let sa = a.signum();
-            let abs_a = a.iabs();
-            let sb = b.signum();
-            let abs_b = b.iabs();
-            if abs_a < 2 || abs_b < 2 {
-                return result;
-            }
-            if sa == sb {
-                if abs_a > unchecked_div(<$ty>::max_value(), abs_b) {
-                    *overflow = 1;
-                }
-            } else {
-                if abs_a > unchecked_div(<$ty>::min_value(), abs_b.unchecked_neg()) {
-                    *overflow = 1;
-                }
-            }
-            result
-        }}
-    }
-
-    pub trait LargeInt {
-        type LowHalf;
-        type HighHalf;
-
-        fn low(self) -> Self::LowHalf;
-        fn high(self) -> Self::HighHalf;
-        fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
-    }
-    impl LargeInt for u128 {
-        type LowHalf = u64;
-        type HighHalf = u64;
-
-        fn low(self) -> u64 {
-            self as u64
-        }
-        fn high(self) -> u64 {
-            self.wrapping_shr(64) as u64
-        }
-        fn from_parts(low: u64, high: u64) -> u128 {
-            (high as u128).wrapping_shl(64) | low as u128
-        }
-    }
-    impl LargeInt for i128 {
-        type LowHalf = u64;
-        type HighHalf = i64;
-
-        fn low(self) -> u64 {
-            self as u64
-        }
-        fn high(self) -> i64 {
-            self.wrapping_shr(64) as i64
-        }
-        fn from_parts(low: u64, high: i64) -> i128 {
-            u128::from_parts(low, high as u64) as i128
-        }
-    }
-
-    macro_rules! mul {
-        ($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{
-            let (a, b) = ($a, $b);
-            let half_bits = ::core::mem::size_of::<$tyh>().wrapping_mul(4) as u32;
-            let lower_mask = (!0u64).wrapping_shr(half_bits);
-            let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
-            let mut t = low.wrapping_shr(half_bits);
-            low &= lower_mask;
-            t = t.wrapping_add(a.low().wrapping_shr(half_bits)
-                                      .wrapping_mul(b.low() & lower_mask));
-            low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits));
-            let mut high = t.wrapping_shr(half_bits) as $tyh;
-            t = low.wrapping_shr(half_bits);
-            low &= lower_mask;
-            t = t.wrapping_add(b.low().wrapping_shr(half_bits)
-                                      .wrapping_mul(a.low() & lower_mask));
-            low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits));
-            high = high.wrapping_add(t.wrapping_shr(half_bits) as $tyh);
-            high = high.wrapping_add(a.low().wrapping_shr(half_bits)
-                           .wrapping_mul(b.low().wrapping_shr(half_bits)) as $tyh);
-            high = high
-                .wrapping_add(a.high()
-                .wrapping_mul(b.low() as $tyh))
-                .wrapping_add((a.low() as $tyh)
-                .wrapping_mul(b.high()));
-            <$ty>::from_parts(low, high)
-        }}
-    }
-
-    #[export_name="__multi3"]
-    pub extern "C" fn u128_mul(a: i128, b: i128) -> i128 {
-        mul!(a, b, i128, i64)
-    }
-
-    trait AbsExt: Sized {
-        fn uabs(self) -> u128;
-        fn iabs(self) -> i128;
-    }
-
-    impl AbsExt for i128 {
-        fn uabs(self) -> u128 {
-            self.iabs() as u128
-        }
-        fn iabs(self) -> i128 {
-            let s = self.wrapping_shr(127);
-            ((self ^ s).wrapping_sub(s))
-        }
-    }
-
-    trait NegExt: Sized {
-        fn unchecked_neg(self) -> i128;
-    }
-
-    impl NegExt for i128 {
-        fn unchecked_neg(self) -> i128 {
-            (!self).wrapping_add(1)
-        }
-    }
-
-    trait FloatStuff: Sized {
-        type ToBytes;
-
-        const MANTISSA_BITS: u32;
-        const MAX_EXP: i32;
-        const EXP_MASK: Self::ToBytes;
-        const MANTISSA_MASK: Self::ToBytes;
-        const MANTISSA_LEAD_BIT: Self::ToBytes;
-
-        fn to_bytes(self) -> Self::ToBytes;
-        fn get_exponent(self) -> i32;
-    }
-
-    impl FloatStuff for f32 {
-        type ToBytes = u32;
-        const MANTISSA_BITS: u32 = 23;
-        const MAX_EXP: i32 = 127;
-        const EXP_MASK: u32 = 0x7F80_0000;
-        const MANTISSA_MASK: u32 = 0x007F_FFFF;
-        const MANTISSA_LEAD_BIT: u32 = 0x0080_0000;
-
-        fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } }
-        fn get_exponent(self) -> i32 {
-            ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32)
-            .wrapping_sub(Self::MAX_EXP)
-        }
-    }
-
-    impl FloatStuff for f64 {
-        type ToBytes = u64;
-        const MANTISSA_BITS: u32 = 52;
-        const MAX_EXP: i32 = 1023;
-        const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
-        const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
-        const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000;
-
-        fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } }
-        fn get_exponent(self) -> i32 {
-            ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32)
-            .wrapping_sub(Self::MAX_EXP)
-        }
-    }
-
-    macro_rules! float_as_unsigned {
-        ($from: expr, $fromty: ty, $outty: ty) => { {
-            use core::num::Float;
-            let repr = $from.to_bytes();
-            let sign = $from.signum();
-            let exponent = $from.get_exponent();
-            let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
-            let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
-            if sign == -1.0 || exponent < 0 { return 0 as u128; }
-            if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 {
-                return !(0 as u128);
-            }
-            (if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
-                (mantissa as $outty)
-                    .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
-                                  .wrapping_sub(exponent) as u32)
-            } else {
-                (mantissa as $outty)
-                    .wrapping_shl(exponent.wrapping_sub(
-                        <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
-            })
-        } }
-    }
-
-    macro_rules! float_as_signed {
-        ($from: expr, $fromty: ty, $outty: ty) => {{
-            use core::num::Float;
-            let repr = $from.to_bytes();
-            let sign = $from.signum();
-            let exponent = $from.get_exponent();
-            let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
-            let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
-
-            if exponent < 0 { return 0 as i128; }
-            if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 {
-                let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() };
-                return ret
-            }
-            let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
-                (mantissa as $outty)
-                    .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
-                                  .wrapping_sub(exponent) as u32)
-            } else {
-                (mantissa as $outty)
-                    .wrapping_shl(exponent.wrapping_sub(
-                        <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
-            };
-            (if sign >= 0.0 { r } else { r.unchecked_neg() })
-        }}
-    }
-
-
-    fn i128_as_f64(a: i128) -> f64 {
-        match a.signum() {
-            1 => u128_as_f64(a.uabs()),
-            0 => 0.0,
-            _ => -u128_as_f64(a.uabs()),
-        }
-    }
-
-    fn i128_as_f32(a: i128) -> f32 {
-        match a.signum() {
-            1 => u128_as_f32(a.uabs()),
-            0 => 0.0,
-            _ => -u128_as_f32(a.uabs()),
-        }
-    }
-
-    fn u128_as_f64(mut a: u128) -> f64 {
-        use ::core::f64::MANTISSA_DIGITS;
-        if a == 0 { return 0.0; }
-        let sd = 128u32.wrapping_sub(a.leading_zeros());
-        let mut e = sd.wrapping_sub(1);
-        const MD1 : u32 = MANTISSA_DIGITS + 1;
-        const MD2 : u32 = MANTISSA_DIGITS + 2;
-
-        let negn = !0u128;
-
-        if sd > MANTISSA_DIGITS {
-            a = match sd {
-                MD1 => a.wrapping_shl(1),
-                MD2 => a,
-                _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) |
-                     (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2)
-                                   .wrapping_sub(sd as u128))) == 0 { 0 } else { 1 })
-            };
-            a |= if (a & 4) == 0 { 0 } else { 1 };
-            a = a.wrapping_add(1);
-            a = a.wrapping_shr(2);
-            if a & (1 << MANTISSA_DIGITS) != 0 {
-                a = a.wrapping_shr(1);
-                e = e.wrapping_add(1);
-            }
-        } else {
-            a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd));
-        }
-        unsafe {
-            ::core::mem::transmute((e as u64).wrapping_add(1023).wrapping_shl(52)
-                                   | (a as u64 & 0x000f_ffff_ffff_ffff))
-        }
-    }
-
-    fn u128_as_f32(mut a: u128) -> f32 {
-        use ::core::f32::MANTISSA_DIGITS;
-        if a == 0 { return 0.0; }
-        let sd = 128u32.wrapping_sub(a.leading_zeros());
-        let mut e = sd.wrapping_sub(1);
-        const MD1 : u32 = MANTISSA_DIGITS + 1;
-        const MD2 : u32 = MANTISSA_DIGITS + 2;
-
-        let negn = !0u128;
-
-        if sd > MANTISSA_DIGITS {
-            a = match sd {
-                MD1 => a.wrapping_shl(1),
-                MD2 => a,
-                _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) |
-                     (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2)
-                                   .wrapping_sub(sd as u128))) == 0 { 0 } else { 1 })
-            };
-            a |= if (a & 4) == 0 { 0 } else { 1 };
-            a = a.wrapping_add(1);
-            a = a.wrapping_shr(2);
-            if a & (1 << MANTISSA_DIGITS) != 0 {
-                a = a.wrapping_shr(1);
-                e = e.wrapping_add(1);
-            }
-        } else {
-            a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd));
-        }
-        unsafe {
-            ::core::mem::transmute((e as u32).wrapping_add(127).wrapping_shl(23)
-                                   | (a as u32 & 0x007f_ffff))
-        }
-    }
-
-
-    macro_rules! why_are_abi_strings_checked_by_parser { ($cret:ty, $conv:expr, $unadj:tt) => {
-    mod imp {
-        use super::{LargeInt, FloatStuff, NegExt, AbsExt};
-        use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32,
-                    i128_div, i128_mod, u128_div_mod, unchecked_div, ptr};
-        // For x64
-        // rdx:rcx, r9:r8, stack -> rdx:rax
-        // aka.
-        // define i128 @__muloti4(i128, i128, i32*)
-        #[export_name="__muloti4"]
-        pub unsafe extern $unadj fn i128_mul_oflow(a: i128, b: i128, o: *mut i32) -> i128 {
-            mulo!(a, b, o, i128)
-        }
-
-        // For x64
-        // rdx:rax -> xmm0
-        // aka.
-        // define double @__muloti4(i128)
-        #[export_name="__floattidf"]
-        pub extern $unadj fn i128_as_f64_(a: i128) -> f64 {
-            i128_as_f64(a)
-        }
-        #[export_name="__floattisf"]
-        pub extern $unadj fn i128_as_f32_(a: i128) -> f32 {
-            i128_as_f32(a)
-        }
-        #[export_name="__floatuntidf"]
-        pub extern $unadj fn u128_as_f64_(a: u128) -> f64 {
-            u128_as_f64(a)
-        }
-        #[export_name="__floatuntisf"]
-        pub extern $unadj fn u128_as_f32_(a: u128) -> f32 {
-            u128_as_f32(a)
-        }
-
-        // For x64
-        // xmm0 -> rdx:rax
-        // aka.
-        // define i128 @stuff(double)
-        #[export_name="__fixunsdfti"]
-        pub extern $unadj fn f64_as_u128(a: f64) -> u128 {
-            float_as_unsigned!(a, f64, u128)
-        }
-
-        #[export_name="__fixunssfti"]
-        pub extern $unadj fn f32_as_u128(a: f32) -> u128 {
-            float_as_unsigned!(a, f32, u128)
-        }
-
-        #[export_name="__fixdfti"]
-        pub extern $unadj fn f64_as_i128(a: f64) -> i128 {
-            float_as_signed!(a, f64, i128)
-        }
-
-        #[export_name="__fixsfti"]
-        pub extern $unadj fn f32_as_i128(a: f32) -> i128 {
-            float_as_signed!(a, f32, i128)
-        }
-
-        #[repr(simd)]
-        pub struct u64x2(u64, u64);
-
-        // For x64
-        // pointers -> xmm0
-        // aka.
-        // define <2 x u64> @stuff(i128*, i128*, i128*)
-        //
-        // That almost matches the C ABI, so we simply use the C ABI
-        #[export_name="__udivmodti4"]
-        pub extern "C" fn u128_div_mod_(n: u128, d: u128, rem: *mut u128) -> $cret {
-            let x = u128_div_mod(n, d, rem);
-            ($conv)(x)
-        }
-
-        #[export_name="__udivti3"]
-        pub extern "C" fn u128_div_(a: u128, b: u128) -> $cret {
-            let x = u128_div_mod(a, b, ptr::null_mut());
-            ($conv)(x)
-        }
-
-        #[export_name="__umodti3"]
-        pub extern "C" fn u128_mod_(a: u128, b: u128) -> $cret {
-            unsafe {
-                let mut r = ::core::mem::zeroed();
-                u128_div_mod(a, b, &mut r);
-                ($conv)(r)
-            }
-        }
-
-        #[export_name="__divti3"]
-        pub extern "C" fn i128_div_(a: i128, b: i128) -> $cret {
-            let x = i128_div(a, b);
-            ($conv)(x as u128)
-        }
-
-        #[export_name="__modti3"]
-        pub extern "C" fn i128_mod_(a: i128, b: i128) -> $cret {
-            let x = i128_mod(a, b);
-            ($conv)(x as u128)
-        }
-    }
-    } }
-
-    // LLVM expectations for ABI on windows x64 are pure madness.
-    #[cfg(all(windows, target_pointer_width="64"))]
-    why_are_abi_strings_checked_by_parser!(u64x2,
-                                           |i: u128| u64x2(i.low(), i.high()),
-                                           "unadjusted");
-
-    #[cfg(not(all(windows, target_pointer_width="64")))]
-    why_are_abi_strings_checked_by_parser!(u128, |i|{ i }, "C");
-    pub use self::imp::*;
-}
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index 7882a8ce5c8ec..f133bd93c9178 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -343,7 +343,7 @@ impl Ordering {
 /// ```
 #[derive(PartialEq, Eq, Debug)]
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
-pub struct Reverse<T>(pub T);
+pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
 
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
 impl<T: PartialOrd> PartialOrd for Reverse<T> {
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs
index 102e3c0bd7b95..322df6e5b47c6 100644
--- a/src/libcore/fmt/builders.rs
+++ b/src/libcore/fmt/builders.rs
@@ -49,9 +49,37 @@ impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
     }
 }
 
-/// A struct to help with `fmt::Debug` implementations.
+/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
 ///
-/// Constructed by the `Formatter::debug_struct` method.
+/// This is useful when you wish to output a formatted struct as a part of your
+/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+///
+/// This can be constructed by the
+/// [`Formatter::debug_struct`](struct.Formatter.html#method.debug_struct)
+/// method.
+///
+/// # Example
+///
+/// ```
+/// use std::fmt;
+///
+/// struct Foo {
+///     bar: i32,
+///     baz: String,
+/// }
+///
+/// impl fmt::Debug for Foo {
+///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+///         fmt.debug_struct("Foo")
+///            .field("bar", &self.bar)
+///            .field("baz", &self.baz)
+///            .finish()
+///     }
+/// }
+///
+/// // prints "Foo { bar: 10, baz: "Hello World" }"
+/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() });
+/// ```
 #[must_use]
 #[allow(missing_debug_implementations)]
 #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -116,9 +144,34 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
     }
 }
 
-/// A struct to help with `fmt::Debug` implementations.
+/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+///
+/// This is useful when you wish to output a formatted tuple as a part of your
+/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+///
+/// This can be constructed by the
+/// [`Formatter::debug_tuple`](struct.Formatter.html#method.debug_tuple)
+/// method.
 ///
-/// Constructed by the `Formatter::debug_tuple` method.
+/// # Example
+///
+/// ```
+/// use std::fmt;
+///
+/// struct Foo(i32, String);
+///
+/// impl fmt::Debug for Foo {
+///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+///         fmt.debug_tuple("Foo")
+///            .field(&self.0)
+///            .field(&self.1)
+///            .finish()
+///     }
+/// }
+///
+/// // prints "Foo(10, "Hello World")"
+/// println!("{:?}", Foo(10, "Hello World".to_string()));
+/// ```
 #[must_use]
 #[allow(missing_debug_implementations)]
 #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -228,9 +281,31 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
     }
 }
 
-/// A struct to help with `fmt::Debug` implementations.
+/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+///
+/// This is useful when you wish to output a formatted set of items as a part
+/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+///
+/// This can be constructed by the
+/// [`Formatter::debug_set`](struct.Formatter.html#method.debug_set)
+/// method.
+///
+/// # Example
 ///
-/// Constructed by the `Formatter::debug_set` method.
+/// ```
+/// use std::fmt;
+///
+/// struct Foo(Vec<i32>);
+///
+/// impl fmt::Debug for Foo {
+///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+///         fmt.debug_set().entries(self.0.iter()).finish()
+///     }
+/// }
+///
+/// // prints "{10, 11}"
+/// println!("{:?}", Foo(vec![10, 11]));
+/// ```
 #[must_use]
 #[allow(missing_debug_implementations)]
 #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -277,9 +352,31 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
     }
 }
 
-/// A struct to help with `fmt::Debug` implementations.
+/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+///
+/// This is useful when you wish to output a formatted list of items as a part
+/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+///
+/// This can be constructed by the
+/// [`Formatter::debug_list`](struct.Formatter.html#method.debug_list)
+/// method.
+///
+/// # Example
+///
+/// ```
+/// use std::fmt;
+///
+/// struct Foo(Vec<i32>);
 ///
-/// Constructed by the `Formatter::debug_list` method.
+/// impl fmt::Debug for Foo {
+///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+///         fmt.debug_list().entries(self.0.iter()).finish()
+///     }
+/// }
+///
+/// // prints "[10, 11]"
+/// println!("{:?}", Foo(vec![10, 11]));
+/// ```
 #[must_use]
 #[allow(missing_debug_implementations)]
 #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -326,9 +423,31 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
     }
 }
 
-/// A struct to help with `fmt::Debug` implementations.
+/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+///
+/// This is useful when you wish to output a formatted map as a part of your
+/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+///
+/// This can be constructed by the
+/// [`Formatter::debug_map`](struct.Formatter.html#method.debug_map)
+/// method.
+///
+/// # Example
+///
+/// ```
+/// use std::fmt;
+///
+/// struct Foo(Vec<(String, i32)>);
+///
+/// impl fmt::Debug for Foo {
+///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+///         fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
+///     }
+/// }
 ///
-/// Constructed by the `Formatter::debug_map` method.
+/// // prints "{"A": 10, "B": 11}"
+/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
+/// ```
 #[must_use]
 #[allow(missing_debug_implementations)]
 #[stable(feature = "debug_builders", since = "1.2.0")]
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index d6a9be4437d43..decd718d65e15 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -314,12 +314,6 @@ pub use self::iterator::Iterator;
            reason = "likely to be replaced by finer-grained traits",
            issue = "42168")]
 pub use self::range::Step;
-#[unstable(feature = "step_by", reason = "recent addition",
-           issue = "27741")]
-#[rustc_deprecated(since = "1.19.0",
-                   reason = "replaced by `iter::StepBy`")]
-#[allow(deprecated)]
-pub use self::range::StepBy as DeprecatedStepBy;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::sources::{Repeat, repeat};
diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs
index 9aea4477fb7fc..1dad815794895 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -244,219 +244,6 @@ step_impl_signed!(i64);
 step_impl_no_between!(u64 i64);
 step_impl_no_between!(u128 i128);
 
-/// An adapter for stepping range iterators by a custom amount.
-///
-/// The resulting iterator handles overflow by stopping. The `A`
-/// parameter is the type being iterated over, while `R` is the range
-/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`.
-#[derive(Clone, Debug)]
-#[unstable(feature = "step_by", reason = "recent addition",
-           issue = "27741")]
-#[rustc_deprecated(since = "1.19.0",
-                   reason = "replaced by `iter::StepBy`")]
-#[allow(deprecated)]
-pub struct StepBy<A, R> {
-    step_by: A,
-    range: R,
-}
-
-impl<A: Step> ops::RangeFrom<A> {
-    /// Creates an iterator starting at the same point, but stepping by
-    /// the given amount at each iteration.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(step_by)]
-    /// fn main() {
-    ///     let result: Vec<_> = (0..).step_by(2).take(5).collect();
-    ///     assert_eq!(result, vec![0, 2, 4, 6, 8]);
-    /// }
-    /// ```
-    #[unstable(feature = "step_by", reason = "recent addition",
-               issue = "27741")]
-    #[rustc_deprecated(since = "1.19.0",
-                       reason = "replaced by `Iterator::step_by`")]
-    #[allow(deprecated)]
-    pub fn step_by(self, by: A) -> StepBy<A, Self> {
-        StepBy {
-            step_by: by,
-            range: self
-        }
-    }
-}
-
-impl<A: Step> ops::Range<A> {
-    /// Creates an iterator with the same range, but stepping by the
-    /// given amount at each iteration.
-    ///
-    /// The resulting iterator handles overflow by stopping.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(step_by)]
-    /// fn main() {
-    ///     let result: Vec<_> = (0..10).step_by(2).collect();
-    ///     assert_eq!(result, vec![0, 2, 4, 6, 8]);
-    /// }
-    /// ```
-    #[unstable(feature = "step_by", reason = "recent addition",
-               issue = "27741")]
-    #[rustc_deprecated(since = "1.19.0",
-                       reason = "replaced by `Iterator::step_by`")]
-    #[allow(deprecated)]
-    pub fn step_by(self, by: A) -> StepBy<A, Self> {
-        StepBy {
-            step_by: by,
-            range: self
-        }
-    }
-}
-
-impl<A: Step> ops::RangeInclusive<A> {
-    /// Creates an iterator with the same range, but stepping by the
-    /// given amount at each iteration.
-    ///
-    /// The resulting iterator handles overflow by stopping.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(step_by, inclusive_range_syntax)]
-    ///
-    /// let result: Vec<_> = (0...10).step_by(2).collect();
-    /// assert_eq!(result, vec![0, 2, 4, 6, 8, 10]);
-    /// ```
-    #[unstable(feature = "step_by", reason = "recent addition",
-               issue = "27741")]
-    #[rustc_deprecated(since = "1.19.0",
-                       reason = "replaced by `Iterator::step_by`")]
-    #[allow(deprecated)]
-    pub fn step_by(self, by: A) -> StepBy<A, Self> {
-        StepBy {
-            step_by: by,
-            range: self
-        }
-    }
-}
-
-#[unstable(feature = "step_by", reason = "recent addition",
-           issue = "27741")]
-#[allow(deprecated)]
-impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
-    A: Clone,
-    for<'a> &'a A: Add<&'a A, Output = A>
-{
-    type Item = A;
-
-    #[inline]
-    fn next(&mut self) -> Option<A> {
-        let mut n = &self.range.start + &self.step_by;
-        mem::swap(&mut n, &mut self.range.start);
-        Some(n)
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (usize::MAX, None) // Too bad we can't specify an infinite lower bound
-    }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-#[allow(deprecated)]
-impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>>
-    where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {}
-
-#[unstable(feature = "step_by", reason = "recent addition",
-           issue = "27741")]
-#[allow(deprecated)]
-impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> {
-    type Item = A;
-
-    #[inline]
-    fn next(&mut self) -> Option<A> {
-        let rev = self.step_by.is_negative();
-        if (rev && self.range.start > self.range.end) ||
-           (!rev && self.range.start < self.range.end)
-        {
-            match self.range.start.step(&self.step_by) {
-                Some(mut n) => {
-                    mem::swap(&mut self.range.start, &mut n);
-                    Some(n)
-                },
-                None => {
-                    let mut n = self.range.end.clone();
-                    mem::swap(&mut self.range.start, &mut n);
-                    Some(n)
-                }
-            }
-        } else {
-            None
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match Step::steps_between(&self.range.start,
-                                  &self.range.end,
-                                  &self.step_by) {
-            Some(hint) => (hint, Some(hint)),
-            None       => (0, None)
-        }
-    }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-#[allow(deprecated)]
-impl<A: Step + Clone> FusedIterator for StepBy<A, ops::Range<A>> {}
-
-#[unstable(feature = "inclusive_range",
-           reason = "recently added, follows RFC",
-           issue = "28237")]
-#[allow(deprecated)]
-impl<A: Step + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
-    type Item = A;
-
-    #[inline]
-    fn next(&mut self) -> Option<A> {
-        let rev = self.step_by.is_negative();
-
-        if (rev && self.range.start >= self.range.end) ||
-           (!rev && self.range.start <= self.range.end)
-        {
-            match self.range.start.step(&self.step_by) {
-                Some(n) => {
-                    Some(mem::replace(&mut self.range.start, n))
-                },
-                None => {
-                    let last = self.range.start.replace_one();
-                    self.range.end.replace_zero();
-                    self.step_by.replace_one();
-                    Some(last)
-                },
-            }
-        }
-        else {
-            None
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match Step::steps_between(&self.range.start,
-                                  &self.range.end,
-                                  &self.step_by) {
-            Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
-            None       => (0, None)
-        }
-    }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-#[allow(deprecated)]
-impl<A: Step + Clone> FusedIterator for StepBy<A, ops::RangeInclusive<A>> {}
-
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index 4f9951cd15399..14f0260f57129 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -12,15 +12,6 @@ use core::iter::*;
 use core::{i8, i16, isize};
 use core::usize;
 
-// FIXME #27741: This is here to simplify calling Iterator::step_by. Remove
-// once Range::step_by is completely gone (not just deprecated).
-trait IterEx: Sized {
-    fn iter_step_by(self, n: usize) -> StepBy<Self>;
-}
-impl<I:Iterator> IterEx for I {
-    fn iter_step_by(self, n: usize) -> StepBy<Self> { self.step_by(n) }
-}
-
 #[test]
 fn test_lt() {
     let empty: [isize; 0] = [];
@@ -76,7 +67,7 @@ fn test_multi_iter() {
 
 #[test]
 fn test_counter_from_iter() {
-    let it = (0..).iter_step_by(5).take(10);
+    let it = (0..).step_by(5).take(10);
     let xs: Vec<isize> = FromIterator::from_iter(it);
     assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
 }
@@ -94,7 +85,7 @@ fn test_iterator_chain() {
     }
     assert_eq!(i, expected.len());
 
-    let ys = (30..).iter_step_by(10).take(4);
+    let ys = (30..).step_by(10).take(4);
     let it = xs.iter().cloned().chain(ys);
     let mut i = 0;
     for x in it {
@@ -156,13 +147,13 @@ fn test_iterator_chain_find() {
 #[test]
 fn test_iterator_step_by() {
     // Identity
-    let mut it = (0..).iter_step_by(1).take(3);
+    let mut it = (0..).step_by(1).take(3);
     assert_eq!(it.next(), Some(0));
     assert_eq!(it.next(), Some(1));
     assert_eq!(it.next(), Some(2));
     assert_eq!(it.next(), None);
 
-    let mut it = (0..).iter_step_by(3).take(4);
+    let mut it = (0..).step_by(3).take(4);
     assert_eq!(it.next(), Some(0));
     assert_eq!(it.next(), Some(3));
     assert_eq!(it.next(), Some(6));
@@ -173,7 +164,7 @@ fn test_iterator_step_by() {
 #[test]
 #[should_panic]
 fn test_iterator_step_by_zero() {
-    let mut it = (0..).iter_step_by(0);
+    let mut it = (0..).step_by(0);
     it.next();
 }
 
@@ -252,7 +243,7 @@ fn test_iterator_step_by_size_hint() {
 
 #[test]
 fn test_filter_map() {
-    let it = (0..).iter_step_by(1).take(10)
+    let it = (0..).step_by(1).take(10)
         .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
     assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
 }
@@ -654,7 +645,7 @@ fn test_iterator_scan() {
 fn test_iterator_flat_map() {
     let xs = [0, 3, 6];
     let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    let it = xs.iter().flat_map(|&x| (x..).iter_step_by(1).take(3));
+    let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
     let mut i = 0;
     for x in it {
         assert_eq!(x, ys[i]);
@@ -680,13 +671,13 @@ fn test_inspect() {
 #[test]
 fn test_cycle() {
     let cycle_len = 3;
-    let it = (0..).iter_step_by(1).take(cycle_len).cycle();
+    let it = (0..).step_by(1).take(cycle_len).cycle();
     assert_eq!(it.size_hint(), (usize::MAX, None));
     for (i, x) in it.take(100).enumerate() {
         assert_eq!(i % cycle_len, x);
     }
 
-    let mut it = (0..).iter_step_by(1).take(0).cycle();
+    let mut it = (0..).step_by(1).take(0).cycle();
     assert_eq!(it.size_hint(), (0, Some(0)));
     assert_eq!(it.next(), None);
 }
@@ -765,7 +756,7 @@ fn test_iterator_min() {
 
 #[test]
 fn test_iterator_size_hint() {
-    let c = (0..).iter_step_by(1);
+    let c = (0..).step_by(1);
     let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
     let v2 = &[10, 11, 12];
     let vi = v.iter();
@@ -1090,8 +1081,8 @@ fn test_range_step() {
     #![allow(deprecated)]
 
     assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]);
-    assert_eq!((20..0).step_by(-5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
-    assert_eq!((20..0).step_by(-6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
+    assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
+    assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
     assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]);
     assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);
     assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []);
@@ -1099,13 +1090,12 @@ fn test_range_step() {
     assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20)));
     assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1)));
     assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4)));
-    assert_eq!((20..0).step_by(-5).size_hint(), (4, Some(4)));
-    assert_eq!((20..0).step_by(-6).size_hint(), (4, Some(4)));
+    assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4)));
+    assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4)));
     assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0)));
     assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0)));
-    assert_eq!((0..1).step_by(0).size_hint(), (0, None));
-    assert_eq!((i8::MAX..i8::MIN).step_by(i8::MIN).size_hint(), (2, Some(2)));
-    assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX).size_hint(), (3, Some(3)));
+    assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2)));
+    assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3)));
     assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX)));
 }
 
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index b0a57d97d5eff..8d3e367d2379a 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -35,7 +35,6 @@
 #![feature(slice_rotate)]
 #![feature(sort_internals)]
 #![feature(specialization)]
-#![feature(step_by)]
 #![feature(step_trait)]
 #![feature(test)]
 #![feature(trusted_len)]
diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml
index 7ce65d0fe4dbc..1b5141773a967 100644
--- a/src/libproc_macro/Cargo.toml
+++ b/src/libproc_macro/Cargo.toml
@@ -9,3 +9,4 @@ crate-type = ["dylib"]
 
 [dependencies]
 syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index f3d0521a2af6c..06f9634d70613 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -37,18 +37,26 @@
        test(no_crate_inject, attr(deny(warnings))),
        test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
 
+#![feature(i128_type)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(lang_items)]
 
+#[macro_use]
 extern crate syntax;
+extern crate syntax_pos;
 
-use std::fmt;
+use std::{ascii, fmt, iter};
 use std::str::FromStr;
 
+use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
-use syntax::parse;
-use syntax::tokenstream::TokenStream as TokenStream_;
+use syntax::parse::{self, token, parse_stream_from_source_str};
+use syntax::print::pprust;
+use syntax::symbol::Symbol;
+use syntax::tokenstream;
+use syntax_pos::DUMMY_SP;
+use syntax_pos::SyntaxContext;
 
 /// The main type provided by this crate, representing an abstract stream of
 /// tokens.
@@ -60,17 +68,508 @@ use syntax::tokenstream::TokenStream as TokenStream_;
 /// The API of this type is intentionally bare-bones, but it'll be expanded over
 /// time!
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
-pub struct TokenStream {
-    inner: TokenStream_,
-}
+#[derive(Clone, Debug)]
+pub struct TokenStream(tokenstream::TokenStream);
 
 /// Error returned from `TokenStream::from_str`.
-#[derive(Debug)]
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
+#[derive(Debug)]
 pub struct LexError {
     _inner: (),
 }
 
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
+impl FromStr for TokenStream {
+    type Err = LexError;
+
+    fn from_str(src: &str) -> Result<TokenStream, LexError> {
+        __internal::with_sess(|(sess, mark)| {
+            let src = src.to_string();
+            let name = "<proc-macro source code>".to_string();
+            let call_site = mark.expn_info().unwrap().call_site;
+            let stream = parse::parse_stream_from_source_str(name, src, sess, Some(call_site));
+            Ok(__internal::token_stream_wrap(stream))
+        })
+    }
+}
+
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
+impl fmt::Display for TokenStream {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input.
+/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs
+/// constructs the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`.
+///
+/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
+/// To quote `$` itself, use `$$`.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[macro_export]
+macro_rules! quote { () => {} }
+
+#[unstable(feature = "proc_macro_internals", issue = "27812")]
+#[doc(hidden)]
+mod quote;
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<TokenTree> for TokenStream {
+    fn from(tree: TokenTree) -> TokenStream {
+        TokenStream(tree.to_internal())
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<TokenNode> for TokenStream {
+    fn from(kind: TokenNode) -> TokenStream {
+        TokenTree::from(kind).into()
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
+    fn from_iter<I: IntoIterator<Item = T>>(streams: I) -> Self {
+        let mut builder = tokenstream::TokenStreamBuilder::new();
+        for stream in streams {
+            builder.push(stream.into().0);
+        }
+        TokenStream(builder.build())
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl IntoIterator for TokenStream {
+    type Item = TokenTree;
+    type IntoIter = TokenTreeIter;
+
+    fn into_iter(self) -> TokenTreeIter {
+        TokenTreeIter { cursor: self.0.trees(), next: None }
+    }
+}
+
+impl TokenStream {
+    /// Returns an empty `TokenStream`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn empty() -> TokenStream {
+        TokenStream(tokenstream::TokenStream::empty())
+    }
+
+    /// Checks if this `TokenStream` is empty.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
+/// A region of source code, along with macro expansion information.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Copy, Clone, Debug)]
+pub struct Span(syntax_pos::Span);
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl Default for Span {
+    fn default() -> Span {
+        ::__internal::with_sess(|(_, mark)| Span(syntax_pos::Span {
+            ctxt: SyntaxContext::empty().apply_mark(mark),
+            ..mark.expn_info().unwrap().call_site
+        }))
+    }
+}
+
+/// Quote a `Span` into a `TokenStream`.
+/// This is needed to implement a custom quoter.
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub fn quote_span(span: Span) -> TokenStream {
+    TokenStream(quote::Quote::quote(&span.0))
+}
+
+impl Span {
+    /// The span of the invocation of the current procedural macro.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn call_site() -> Span {
+        ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
+    }
+}
+
+/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Clone, Debug)]
+pub struct TokenTree {
+    /// The `TokenTree`'s span
+    pub span: Span,
+    /// Description of the `TokenTree`
+    pub kind: TokenNode,
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<TokenNode> for TokenTree {
+    fn from(kind: TokenNode) -> TokenTree {
+        TokenTree { span: Span::default(), kind: kind }
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl fmt::Display for TokenTree {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        TokenStream::from(self.clone()).fmt(f)
+    }
+}
+
+/// Description of a `TokenTree`
+#[derive(Clone, Debug)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub enum TokenNode {
+    /// A delimited tokenstream.
+    Group(Delimiter, TokenStream),
+    /// A unicode identifier.
+    Term(Term),
+    /// A punctuation character (`+`, `,`, `$`, etc.).
+    Op(char, Spacing),
+    /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
+    Literal(Literal),
+}
+
+/// Describes how a sequence of token trees is delimited.
+#[derive(Copy, Clone, Debug)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub enum Delimiter {
+    /// `( ... )`
+    Parenthesis,
+    /// `[ ... ]`
+    Brace,
+    /// `{ ... }`
+    Bracket,
+    /// An implicit delimiter, e.g. `$var`, where $var is  `...`.
+    None,
+}
+
+/// An interned string.
+#[derive(Copy, Clone, Debug)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub struct Term(Symbol);
+
+impl Term {
+    /// Intern a string into a `Term`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn intern(string: &str) -> Term {
+        Term(Symbol::intern(string))
+    }
+
+    /// Get a reference to the interned string.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn as_str(&self) -> &str {
+        unsafe { &*(&*self.0.as_str() as *const str) }
+    }
+}
+
+/// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
+#[derive(Copy, Clone, Debug)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub enum Spacing {
+    /// e.g. `+` is `Alone` in `+ =`.
+    Alone,
+    /// e.g. `+` is `Joint` in `+=`.
+    Joint,
+}
+
+/// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
+#[derive(Clone, Debug)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub struct Literal(token::Token);
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl fmt::Display for Literal {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        TokenTree { kind: TokenNode::Literal(self.clone()), span: Span(DUMMY_SP) }.fmt(f)
+    }
+}
+
+macro_rules! int_literals {
+    ($($int_kind:ident),*) => {$(
+        /// Integer literal.
+        #[unstable(feature = "proc_macro", issue = "38356")]
+        pub fn $int_kind(n: $int_kind) -> Literal {
+            Literal::typed_integer(n as i128, stringify!($int_kind))
+        }
+    )*}
+}
+
+impl Literal {
+    /// Integer literal
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn integer(n: i128) -> Literal {
+        Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), None))
+    }
+
+    int_literals!(u8, i8, u16, i16, u32, i32, u64, i64);
+    fn typed_integer(n: i128, kind: &'static str) -> Literal {
+        Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())),
+                               Some(Symbol::intern(kind))))
+    }
+
+    /// Floating point literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn float(n: f64) -> Literal {
+        if !n.is_finite() {
+            panic!("Invalid float literal {}", n);
+        }
+        Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), None))
+    }
+
+    /// Floating point literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn f32(n: f32) -> Literal {
+        if !n.is_finite() {
+            panic!("Invalid f32 literal {}", n);
+        }
+        Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())),
+                               Some(Symbol::intern("f32"))))
+    }
+
+    /// Floating point literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn f64(n: f64) -> Literal {
+        if !n.is_finite() {
+            panic!("Invalid f64 literal {}", n);
+        }
+        Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())),
+                               Some(Symbol::intern("f64"))))
+    }
+
+    /// String literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn string(string: &str) -> Literal {
+        let mut escaped = String::new();
+        for ch in string.chars() {
+            escaped.extend(ch.escape_unicode());
+        }
+        Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None))
+    }
+
+    /// Character literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn character(ch: char) -> Literal {
+        let mut escaped = String::new();
+        escaped.extend(ch.escape_unicode());
+        Literal(token::Literal(token::Lit::Char(Symbol::intern(&escaped)), None))
+    }
+
+    /// Byte string literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn byte_string(bytes: &[u8]) -> Literal {
+        let string = bytes.iter().cloned().flat_map(ascii::escape_default)
+            .map(Into::<char>::into).collect::<String>();
+        Literal(token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None))
+    }
+}
+
+/// An iterator over `TokenTree`s.
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub struct TokenTreeIter {
+    cursor: tokenstream::Cursor,
+    next: Option<tokenstream::TokenStream>,
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl Iterator for TokenTreeIter {
+    type Item = TokenTree;
+
+    fn next(&mut self) -> Option<TokenTree> {
+        loop {
+            let next =
+                unwrap_or!(self.next.take().or_else(|| self.cursor.next_as_stream()), return None);
+            let tree = TokenTree::from_internal(next, &mut self.next);
+            if tree.span.0 == DUMMY_SP {
+                if let TokenNode::Group(Delimiter::None, stream) = tree.kind {
+                    self.cursor.insert(stream.0);
+                    continue
+                }
+            }
+            return Some(tree);
+        }
+    }
+}
+
+impl Delimiter {
+    fn from_internal(delim: token::DelimToken) -> Delimiter {
+        match delim {
+            token::Paren => Delimiter::Parenthesis,
+            token::Brace => Delimiter::Brace,
+            token::Bracket => Delimiter::Bracket,
+            token::NoDelim => Delimiter::None,
+        }
+    }
+
+    fn to_internal(self) -> token::DelimToken {
+        match self {
+            Delimiter::Parenthesis => token::Paren,
+            Delimiter::Brace => token::Brace,
+            Delimiter::Bracket => token::Bracket,
+            Delimiter::None => token::NoDelim,
+        }
+    }
+}
+
+impl TokenTree {
+    fn from_internal(stream: tokenstream::TokenStream, next: &mut Option<tokenstream::TokenStream>)
+                -> TokenTree {
+        use syntax::parse::token::*;
+
+        let (tree, is_joint) = stream.as_tree();
+        let (mut span, token) = match tree {
+            tokenstream::TokenTree::Token(span, token) => (span, token),
+            tokenstream::TokenTree::Delimited(span, delimed) => {
+                let delimiter = Delimiter::from_internal(delimed.delim);
+                return TokenTree {
+                    span: Span(span),
+                    kind: TokenNode::Group(delimiter, TokenStream(delimed.tts.into())),
+                };
+            }
+        };
+
+        let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone };
+        macro_rules! op {
+            ($op:expr) => { TokenNode::Op($op, op_kind) }
+        }
+
+        macro_rules! joint {
+            ($first:expr, $rest:expr) => { joint($first, $rest, is_joint, &mut span, next) }
+        }
+
+        fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span,
+                 next: &mut Option<tokenstream::TokenStream>)
+                 -> TokenNode {
+            let (first_span, rest_span) = (*span, *span);
+            *span = first_span;
+            let tree = tokenstream::TokenTree::Token(rest_span, rest);
+            *next = Some(if is_joint { tree.joint() } else { tree.into() });
+            TokenNode::Op(first, Spacing::Joint)
+        }
+
+        let kind = match token {
+            Eq => op!('='),
+            Lt => op!('<'),
+            Le => joint!('<', Eq),
+            EqEq => joint!('=', Eq),
+            Ne => joint!('!', Eq),
+            Ge => joint!('>', Eq),
+            Gt => op!('>'),
+            AndAnd => joint!('&', BinOp(And)),
+            OrOr => joint!('|', BinOp(Or)),
+            Not => op!('!'),
+            Tilde => op!('~'),
+            BinOp(Plus) => op!('+'),
+            BinOp(Minus) => op!('-'),
+            BinOp(Star) => op!('*'),
+            BinOp(Slash) => op!('/'),
+            BinOp(Percent) => op!('%'),
+            BinOp(Caret) => op!('^'),
+            BinOp(And) => op!('&'),
+            BinOp(Or) => op!('|'),
+            BinOp(Shl) => joint!('<', Lt),
+            BinOp(Shr) => joint!('>', Gt),
+            BinOpEq(Plus) => joint!('+', Eq),
+            BinOpEq(Minus) => joint!('-', Eq),
+            BinOpEq(Star) => joint!('*', Eq),
+            BinOpEq(Slash) => joint!('/', Eq),
+            BinOpEq(Percent) => joint!('%', Eq),
+            BinOpEq(Caret) => joint!('^', Eq),
+            BinOpEq(And) => joint!('&', Eq),
+            BinOpEq(Or) => joint!('|', Eq),
+            BinOpEq(Shl) => joint!('<', Le),
+            BinOpEq(Shr) => joint!('>', Ge),
+            At => op!('@'),
+            Dot => op!('.'),
+            DotDot => joint!('.', Dot),
+            DotDotDot => joint!('.', DotDot),
+            Comma => op!(','),
+            Semi => op!(';'),
+            Colon => op!(':'),
+            ModSep => joint!(':', Colon),
+            RArrow => joint!('-', Gt),
+            LArrow => joint!('<', BinOp(Minus)),
+            FatArrow => joint!('=', Gt),
+            Pound => op!('#'),
+            Dollar => op!('$'),
+            Question => op!('?'),
+            Underscore => op!('_'),
+
+            Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)),
+            Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)),
+
+            Interpolated(ref nt) => __internal::with_sess(|(sess, _)| {
+                TokenNode::Group(Delimiter::None, TokenStream(nt.1.force(|| {
+                    // FIXME(jseyfried): Avoid this pretty-print + reparse hack
+                    let name = "<macro expansion>".to_owned();
+                    let source = pprust::token_to_string(&token);
+                    parse_stream_from_source_str(name, source, sess, Some(span))
+                })))
+            }),
+
+            OpenDelim(..) | CloseDelim(..) => unreachable!(),
+            Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
+        };
+
+        TokenTree { span: Span(span), kind: kind }
+    }
+
+    fn to_internal(self) -> tokenstream::TokenStream {
+        use syntax::parse::token::*;
+        use syntax::tokenstream::{TokenTree, Delimited};
+
+        let (op, kind) = match self.kind {
+            TokenNode::Op(op, kind) => (op, kind),
+            TokenNode::Group(delimiter, tokens) => {
+                return TokenTree::Delimited(self.span.0, Delimited {
+                    delim: delimiter.to_internal(),
+                    tts: tokens.0.into(),
+                }).into();
+            },
+            TokenNode::Term(symbol) => {
+                let ident = ast::Ident { name: symbol.0, ctxt: self.span.0.ctxt };
+                let token =
+                    if symbol.0.as_str().starts_with("'") { Lifetime(ident) } else { Ident(ident) };
+                return TokenTree::Token(self.span.0, token).into();
+            }
+            TokenNode::Literal(token) => return TokenTree::Token(self.span.0, token.0).into(),
+        };
+
+        let token = match op {
+            '=' => Eq,
+            '<' => Lt,
+            '>' => Gt,
+            '!' => Not,
+            '~' => Tilde,
+            '+' => BinOp(Plus),
+            '-' => BinOp(Minus),
+            '*' => BinOp(Star),
+            '/' => BinOp(Slash),
+            '%' => BinOp(Percent),
+            '^' => BinOp(Caret),
+            '&' => BinOp(And),
+            '|' => BinOp(Or),
+            '@' => At,
+            '.' => Dot,
+            ',' => Comma,
+            ';' => Semi,
+            ':' => Colon,
+            '#' => Pound,
+            '$' => Dollar,
+            '?' => Question,
+            '_' => Underscore,
+            _ => panic!("unsupported character {}", op),
+        };
+
+        let tree = TokenTree::Token(self.span.0, token);
+        match kind {
+            Spacing::Alone => tree.into(),
+            Spacing::Joint => tree.joint(),
+        }
+    }
+}
+
 /// Permanently unstable internal implementation details of this crate. This
 /// should not be used.
 ///
@@ -83,32 +582,33 @@ pub struct LexError {
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
 pub mod __internal {
+    pub use quote::{Quoter, __rt};
+
     use std::cell::Cell;
-    use std::rc::Rc;
 
     use syntax::ast;
+    use syntax::ext::base::ExtCtxt;
+    use syntax::ext::hygiene::Mark;
     use syntax::ptr::P;
-    use syntax::parse::{self, token, ParseSess};
-    use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_};
+    use syntax::parse::{self, ParseSess};
+    use syntax::parse::token::{self, Token};
+    use syntax::tokenstream;
+    use syntax_pos::DUMMY_SP;
 
     use super::{TokenStream, LexError};
 
     pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
-        TokenStream {
-            inner: TokenTree::Token(item.span, token::Interpolated(Rc::new(token::NtItem(item))))
-                .into()
-        }
+        let token = Token::interpolated(token::NtItem(item));
+        TokenStream(tokenstream::TokenTree::Token(DUMMY_SP, token).into())
     }
 
-    pub fn token_stream_wrap(inner: TokenStream_) -> TokenStream {
-        TokenStream {
-            inner: inner
-        }
+    pub fn token_stream_wrap(inner: tokenstream::TokenStream) -> TokenStream {
+        TokenStream(inner)
     }
 
     pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
-        with_parse_sess(move |sess| {
-            let mut parser = parse::stream_to_parser(sess, stream.inner);
+        with_sess(move |(sess, _)| {
+            let mut parser = parse::stream_to_parser(sess, stream.0);
             let mut items = Vec::new();
 
             while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) {
@@ -119,8 +619,8 @@ pub mod __internal {
         })
     }
 
-    pub fn token_stream_inner(stream: TokenStream) -> TokenStream_ {
-        stream.inner
+    pub fn token_stream_inner(stream: TokenStream) -> tokenstream::TokenStream {
+        stream.0
     }
 
     pub trait Registry {
@@ -140,13 +640,14 @@ pub mod __internal {
 
     // Emulate scoped_thread_local!() here essentially
     thread_local! {
-        static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
+        static CURRENT_SESS: Cell<(*const ParseSess, Mark)> =
+            Cell::new((0 as *const _, Mark::root()));
     }
 
-    pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
+    pub fn set_sess<F, R>(cx: &ExtCtxt, f: F) -> R
         where F: FnOnce() -> R
     {
-        struct Reset { prev: *const ParseSess }
+        struct Reset { prev: (*const ParseSess, Mark) }
 
         impl Drop for Reset {
             fn drop(&mut self) {
@@ -156,18 +657,18 @@ pub mod __internal {
 
         CURRENT_SESS.with(|p| {
             let _reset = Reset { prev: p.get() };
-            p.set(sess);
+            p.set((cx.parse_sess, cx.current_expansion.mark));
             f()
         })
     }
 
-    pub fn with_parse_sess<F, R>(f: F) -> R
-        where F: FnOnce(&ParseSess) -> R
+    pub fn with_sess<F, R>(f: F) -> R
+        where F: FnOnce((&ParseSess, Mark)) -> R
     {
         let p = CURRENT_SESS.with(|p| p.get());
-        assert!(!p.is_null(), "proc_macro::__internal::with_parse_sess() called \
-                               before set_parse_sess()!");
-        f(unsafe { &*p })
+        assert!(!p.0.is_null(), "proc_macro::__internal::with_sess() called \
+                                 before set_parse_sess()!");
+        f(unsafe { (&*p.0, p.1) })
     }
 }
 
@@ -175,24 +676,3 @@ fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
     err.cancel();
     LexError { _inner: () }
 }
-
-#[stable(feature = "proc_macro_lib", since = "1.15.0")]
-impl FromStr for TokenStream {
-    type Err = LexError;
-
-    fn from_str(src: &str) -> Result<TokenStream, LexError> {
-        __internal::with_parse_sess(|sess| {
-            let src = src.to_string();
-            let name = "<proc-macro source code>".to_string();
-            let stream = parse::parse_stream_from_source_str(name, src, sess);
-            Ok(__internal::token_stream_wrap(stream))
-        })
-    }
-}
-
-#[stable(feature = "proc_macro_lib", since = "1.15.0")]
-impl fmt::Display for TokenStream {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.inner.fmt(f)
-    }
-}
diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs
new file mode 100644
index 0000000000000..bee2c1e0eb6b6
--- /dev/null
+++ b/src/libproc_macro/quote.rs
@@ -0,0 +1,263 @@
+// 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.
+
+//! # Quasiquoter
+//! This file contains the implementation internals of the quasiquoter provided by `quote!`.
+
+//! This quasiquoter uses macros 2.0 hygiene to reliably use items from `__rt`,
+//! including re-exported API `libsyntax`, to build a `syntax::tokenstream::TokenStream`
+//! and wrap it into a `proc_macro::TokenStream`.
+
+use syntax::ast::Ident;
+use syntax::ext::base::{ExtCtxt, ProcMacro};
+use syntax::parse::token::{self, Token, Lit};
+use syntax::symbol::Symbol;
+use syntax::tokenstream::{Delimited, TokenTree, TokenStream, TokenStreamBuilder};
+use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::hygiene::SyntaxContext;
+
+pub struct Quoter;
+
+pub mod __rt {
+    pub use syntax::ast::Ident;
+    pub use syntax::parse::token;
+    pub use syntax::symbol::Symbol;
+    pub use syntax::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree, Delimited};
+    pub use super::{ctxt, span};
+
+    pub fn unquote<T: Into<::TokenStream> + Clone>(tokens: &T) -> TokenStream {
+        T::into(tokens.clone()).0
+    }
+}
+
+pub fn ctxt() -> SyntaxContext {
+    ::__internal::with_sess(|(_, mark)| SyntaxContext::empty().apply_mark(mark))
+}
+
+pub fn span() -> Span {
+    ::Span::default().0
+}
+
+pub trait Quote {
+    fn quote(&self) -> TokenStream;
+}
+
+macro_rules! quote_tok {
+    (,) => { Token::Comma };
+    (.) => { Token::Dot };
+    (:) => { Token::Colon };
+    (::) => { Token::ModSep };
+    (!) => { Token::Not };
+    (<) => { Token::Lt };
+    (>) => { Token::Gt };
+    (_) => { Token::Underscore };
+    (0) => { Token::Literal(token::Lit::Integer(Symbol::intern("0")), None) };
+    (&) => { Token::BinOp(token::And) };
+    ($i:ident) => { Token::Ident(Ident { name: Symbol::intern(stringify!($i)), ctxt: ctxt() }) };
+}
+
+macro_rules! quote_tree {
+    ((unquote $($t:tt)*)) => { TokenStream::from($($t)*) };
+    ((quote $($t:tt)*)) => { ($($t)*).quote() };
+    (($($t:tt)*)) => { delimit(token::Paren, quote!($($t)*)) };
+    ([$($t:tt)*]) => { delimit(token::Bracket, quote!($($t)*)) };
+    ({$($t:tt)*}) => { delimit(token::Brace, quote!($($t)*)) };
+    (rt) => { quote!(::__internal::__rt) };
+    ($t:tt) => { TokenStream::from(TokenTree::Token(span(), quote_tok!($t))) };
+}
+
+fn delimit(delim: token::DelimToken, stream: TokenStream) -> TokenStream {
+    TokenTree::Delimited(span(), Delimited { delim: delim, tts: stream.into() }).into()
+}
+
+macro_rules! quote {
+    () => { TokenStream::empty() };
+    ($($t:tt)*) => { [ $( quote_tree!($t), )* ].iter().cloned().collect::<TokenStream>() };
+}
+
+impl ProcMacro for Quoter {
+    fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, _: Span, stream: TokenStream) -> TokenStream {
+        let mut info = cx.current_expansion.mark.expn_info().unwrap();
+        info.callee.allow_internal_unstable = true;
+        cx.current_expansion.mark.set_expn_info(info);
+        ::__internal::set_sess(cx, || quote!(::TokenStream((quote stream))))
+    }
+}
+
+impl<T: Quote> Quote for Option<T> {
+    fn quote(&self) -> TokenStream {
+        match *self {
+            Some(ref t) => quote!(Some((quote t))),
+            None => quote!(None),
+        }
+    }
+}
+
+impl Quote for TokenStream {
+    fn quote(&self) -> TokenStream {
+        let mut builder = TokenStreamBuilder::new();
+        builder.push(quote!(rt::TokenStreamBuilder::new()));
+
+        let mut trees = self.trees();
+        loop {
+            let (mut tree, mut is_joint) = match trees.next_as_stream() {
+                Some(next) => next.as_tree(),
+                None => return builder.add(quote!(.build())).build(),
+            };
+            if let TokenTree::Token(_, Token::Dollar) = tree {
+                let (next_tree, next_is_joint) = match trees.next_as_stream() {
+                    Some(next) => next.as_tree(),
+                    None => panic!("unexpected trailing `$` in `quote!`"),
+                };
+                match next_tree {
+                    TokenTree::Token(_, Token::Ident(..)) => {
+                        builder.push(quote!(.add(rt::unquote(&(unquote next_tree)))));
+                        continue
+                    }
+                    TokenTree::Token(_, Token::Dollar) => {
+                        tree = next_tree;
+                        is_joint = next_is_joint;
+                    }
+                    _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
+                }
+            }
+
+            builder.push(match is_joint {
+                true => quote!(.add((quote tree).joint())),
+                false => quote!(.add(rt::TokenStream::from((quote tree)))),
+            });
+        }
+    }
+}
+
+impl Quote for TokenTree {
+    fn quote(&self) -> TokenStream {
+        match *self {
+            TokenTree::Token(span, ref token) => quote! {
+                rt::TokenTree::Token((quote span), (quote token))
+            },
+            TokenTree::Delimited(span, ref delimited) => quote! {
+                rt::TokenTree::Delimited((quote span), (quote delimited))
+            },
+        }
+    }
+}
+
+impl Quote for Delimited {
+    fn quote(&self) -> TokenStream {
+        quote!(rt::Delimited { delim: (quote self.delim), tts: (quote self.stream()).into() })
+    }
+}
+
+impl<'a> Quote for &'a str {
+    fn quote(&self) -> TokenStream {
+        TokenTree::Token(span(), Token::Literal(token::Lit::Str_(Symbol::intern(self)), None))
+            .into()
+    }
+}
+
+impl Quote for usize {
+    fn quote(&self) -> TokenStream {
+        let integer_symbol = Symbol::intern(&self.to_string());
+        TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Integer(integer_symbol), None))
+            .into()
+    }
+}
+
+impl Quote for Ident {
+    fn quote(&self) -> TokenStream {
+        quote!(rt::Ident { name: (quote self.name), ctxt: rt::ctxt() })
+    }
+}
+
+impl Quote for Symbol {
+    fn quote(&self) -> TokenStream {
+        quote!(rt::Symbol::intern((quote &*self.as_str())))
+    }
+}
+
+impl Quote for Span {
+    fn quote(&self) -> TokenStream {
+        quote!(rt::span())
+    }
+}
+
+impl Quote for Token {
+    fn quote(&self) -> TokenStream {
+        macro_rules! gen_match {
+            ($($i:ident),*; $($t:tt)*) => {
+                match *self {
+                    $( Token::$i => quote!(rt::token::$i), )*
+                    $( $t )*
+                }
+            }
+        }
+
+        gen_match! {
+            Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot,
+            Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question,
+            Underscore;
+
+            Token::OpenDelim(delim) => quote!(rt::token::OpenDelim((quote delim))),
+            Token::CloseDelim(delim) => quote!(rt::token::CloseDelim((quote delim))),
+            Token::BinOp(tok) => quote!(rt::token::BinOp((quote tok))),
+            Token::BinOpEq(tok) => quote!(rt::token::BinOpEq((quote tok))),
+            Token::Ident(ident) => quote!(rt::token::Ident((quote ident))),
+            Token::Lifetime(ident) => quote!(rt::token::Lifetime((quote ident))),
+            Token::Literal(lit, sfx) => quote!(rt::token::Literal((quote lit), (quote sfx))),
+            _ => panic!("Unhandled case!"),
+        }
+    }
+}
+
+impl Quote for token::BinOpToken {
+    fn quote(&self) -> TokenStream {
+        macro_rules! gen_match {
+            ($($i:ident),*) => {
+                match *self {
+                    $( token::BinOpToken::$i => quote!(rt::token::BinOpToken::$i), )*
+                }
+            }
+        }
+
+        gen_match!(Plus, Minus, Star, Slash, Percent, Caret, And, Or, Shl, Shr)
+    }
+}
+
+impl Quote for Lit {
+    fn quote(&self) -> TokenStream {
+        macro_rules! gen_match {
+            ($($i:ident),*; $($raw:ident),*) => {
+                match *self {
+                    $( Lit::$i(lit) => quote!(rt::token::Lit::$i((quote lit))), )*
+                    $( Lit::$raw(lit, n) => {
+                        quote!(::syntax::parse::token::Lit::$raw((quote lit), (quote n)))
+                    })*
+                }
+            }
+        }
+
+        gen_match!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw)
+    }
+}
+
+impl Quote for token::DelimToken {
+    fn quote(&self) -> TokenStream {
+        macro_rules! gen_match {
+            ($($i:ident),*) => {
+                match *self {
+                    $(token::DelimToken::$i => { quote!(rt::token::DelimToken::$i) })*
+                }
+            }
+        }
+
+        gen_match!(Paren, Bracket, Brace, NoDelim)
+    }
+}
diff --git a/src/libproc_macro_plugin/lib.rs b/src/libproc_macro_plugin/lib.rs
deleted file mode 100644
index d1bc0966eb567..0000000000000
--- a/src/libproc_macro_plugin/lib.rs
+++ /dev/null
@@ -1,103 +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.
-
-//! # Proc_Macro
-//!
-//! A library for procedural macro writers.
-//!
-//! ## Usage
-//! This crate provides the `quote!` macro for syntax creation.
-//!
-//! The `quote!` macro uses the crate `syntax`, so users must declare `extern crate syntax;`
-//! at the crate root. This is a temporary solution until we have better hygiene.
-//!
-//! ## Quasiquotation
-//!
-//! The quasiquoter creates output that, when run, constructs the tokenstream specified as
-//! input. For example, `quote!(5 + 5)` will produce a program, that, when run, will
-//! construct the TokenStream `5 | + | 5`.
-//!
-//! ### Unquoting
-//!
-//! Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
-//! To quote `$` itself, use `$$`.
-//!
-//! A simple example is:
-//!
-//!```
-//!fn double(tmp: TokenStream) -> TokenStream {
-//!    quote!($tmp * 2)
-//!}
-//!```
-//!
-//! ### Large example: Scheme's `cond`
-//!
-//! Below is an example implementation of Scheme's `cond`.
-//!
-//! ```
-//! fn cond(input: TokenStream) -> TokenStream {
-//!     let mut conds = Vec::new();
-//!     let mut input = input.trees().peekable();
-//!     while let Some(tree) = input.next() {
-//!         let mut cond = match tree {
-//!             TokenTree::Delimited(_, ref delimited) => delimited.stream(),
-//!             _ => panic!("Invalid input"),
-//!         };
-//!         let mut trees = cond.trees();
-//!         let test = trees.next();
-//!         let rhs = trees.collect::<TokenStream>();
-//!         if rhs.is_empty() {
-//!             panic!("Invalid macro usage in cond: {}", cond);
-//!         }
-//!         let is_else = match test {
-//!             Some(TokenTree::Token(_, Token::Ident(ident))) if ident.name == "else" => true,
-//!             _ => false,
-//!         };
-//!         conds.push(if is_else || input.peek().is_none() {
-//!             quote!({ $rhs })
-//!         } else {
-//!             let test = test.unwrap();
-//!             quote!(if $test { $rhs } else)
-//!         });
-//!     }
-//!
-//!     conds.into_iter().collect()
-//! }
-//! ```
-#![crate_name = "proc_macro_plugin"]
-#![feature(plugin_registrar)]
-#![crate_type = "dylib"]
-#![crate_type = "rlib"]
-#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
-       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
-       html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(warnings)]
-
-#![feature(rustc_diagnostic_macros)]
-
-extern crate rustc_plugin;
-extern crate syntax;
-extern crate syntax_pos;
-
-mod quote;
-use quote::quote;
-
-use rustc_plugin::Registry;
-use syntax::ext::base::SyntaxExtension;
-use syntax::symbol::Symbol;
-
-// ____________________________________________________________________________________________
-// Main macro definition
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(Symbol::intern("quote"),
-                                  SyntaxExtension::ProcMacro(Box::new(quote)));
-}
diff --git a/src/libproc_macro_plugin/quote.rs b/src/libproc_macro_plugin/quote.rs
deleted file mode 100644
index 09675564291a2..0000000000000
--- a/src/libproc_macro_plugin/quote.rs
+++ /dev/null
@@ -1,230 +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.
-
-//! # Quasiquoter
-//! This file contains the implementation internals of the quasiquoter provided by `qquote!`.
-
-use syntax::ast::Ident;
-use syntax::parse::token::{self, Token, Lit};
-use syntax::symbol::Symbol;
-use syntax::tokenstream::{self, Delimited, TokenTree, TokenStream};
-use syntax_pos::DUMMY_SP;
-
-use std::iter;
-
-pub fn quote<'cx>(stream: TokenStream) -> TokenStream {
-    stream.quote()
-}
-
-trait Quote {
-    fn quote(&self) -> TokenStream;
-}
-
-macro_rules! quote_tok {
-    (,) => { Token::Comma };
-    (.) => { Token::Dot };
-    (:) => { Token::Colon };
-    (::) => { Token::ModSep };
-    (!) => { Token::Not };
-    (<) => { Token::Lt };
-    (>) => { Token::Gt };
-    (_) => { Token::Underscore };
-    ($i:ident) => { Token::Ident(Ident::from_str(stringify!($i))) };
-}
-
-macro_rules! quote_tree {
-    ((unquote $($t:tt)*)) => { $($t)* };
-    ((quote $($t:tt)*)) => { ($($t)*).quote() };
-    (($($t:tt)*)) => { delimit(token::Paren, quote!($($t)*)) };
-    ([$($t:tt)*]) => { delimit(token::Bracket, quote!($($t)*)) };
-    ({$($t:tt)*}) => { delimit(token::Brace, quote!($($t)*)) };
-    ($t:tt) => { TokenStream::from(TokenTree::Token(DUMMY_SP, quote_tok!($t))) };
-}
-
-fn delimit(delim: token::DelimToken, stream: TokenStream) -> TokenStream {
-    TokenTree::Delimited(DUMMY_SP, Delimited { delim: delim, tts: stream.into() }).into()
-}
-
-macro_rules! quote {
-    () => { TokenStream::empty() };
-    ($($t:tt)*) => { [ $( quote_tree!($t), )* ].iter().cloned().collect::<TokenStream>() };
-}
-
-impl<T: Quote> Quote for Option<T> {
-    fn quote(&self) -> TokenStream {
-        match *self {
-            Some(ref t) => quote!(::std::option::Option::Some((quote t))),
-            None => quote!(::std::option::Option::None),
-        }
-    }
-}
-
-impl Quote for TokenStream {
-    fn quote(&self) -> TokenStream {
-        if self.is_empty() {
-            return quote!(::syntax::tokenstream::TokenStream::empty());
-        }
-
-        struct Quoter(iter::Peekable<tokenstream::Cursor>);
-
-        impl Iterator for Quoter {
-            type Item = TokenStream;
-
-            fn next(&mut self) -> Option<TokenStream> {
-                let quoted_tree = if let Some(&TokenTree::Token(_, Token::Dollar)) = self.0.peek() {
-                    self.0.next();
-                    match self.0.next() {
-                        Some(tree @ TokenTree::Token(_, Token::Ident(..))) => Some(tree.into()),
-                        Some(tree @ TokenTree::Token(_, Token::Dollar)) => Some(tree.quote()),
-                        // FIXME(jseyfried): improve these diagnostics
-                        Some(..) => panic!("`$` must be followed by an ident or `$` in `quote!`"),
-                        None => panic!("unexpected trailing `$` in `quote!`"),
-                    }
-                } else {
-                    self.0.next().as_ref().map(Quote::quote)
-                };
-
-                quoted_tree.map(|quoted_tree| {
-                    quote!(::syntax::tokenstream::TokenStream::from((unquote quoted_tree)),)
-                })
-            }
-        }
-
-        let quoted = Quoter(self.trees().peekable()).collect::<TokenStream>();
-        quote!([(unquote quoted)].iter().cloned().collect::<::syntax::tokenstream::TokenStream>())
-    }
-}
-
-impl Quote for TokenTree {
-    fn quote(&self) -> TokenStream {
-        match *self {
-            TokenTree::Token(_, ref token) => quote! {
-                ::syntax::tokenstream::TokenTree::Token(::syntax::ext::quote::rt::DUMMY_SP,
-                                                        (quote token))
-            },
-            TokenTree::Delimited(_, ref delimited) => quote! {
-                ::syntax::tokenstream::TokenTree::Delimited(::syntax::ext::quote::rt::DUMMY_SP,
-                                                            (quote delimited))
-            },
-        }
-    }
-}
-
-impl Quote for Delimited {
-    fn quote(&self) -> TokenStream {
-        quote!(::syntax::tokenstream::Delimited {
-            delim: (quote self.delim),
-            tts: (quote self.stream()).into(),
-        })
-    }
-}
-
-impl<'a> Quote for &'a str {
-    fn quote(&self) -> TokenStream {
-        TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Str_(Symbol::intern(self)), None))
-            .into()
-    }
-}
-
-impl Quote for usize {
-    fn quote(&self) -> TokenStream {
-        let integer_symbol = Symbol::intern(&self.to_string());
-        TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Integer(integer_symbol), None))
-            .into()
-    }
-}
-
-impl Quote for Ident {
-    fn quote(&self) -> TokenStream {
-        // FIXME(jseyfried) quote hygiene
-        quote!(::syntax::ast::Ident::from_str((quote &*self.name.as_str())))
-    }
-}
-
-impl Quote for Symbol {
-    fn quote(&self) -> TokenStream {
-        quote!(::syntax::symbol::Symbol::intern((quote &*self.as_str())))
-    }
-}
-
-impl Quote for Token {
-    fn quote(&self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident),*; $($t:tt)*) => {
-                match *self {
-                    $( Token::$i => quote!(::syntax::parse::token::$i), )*
-                    $( $t )*
-                }
-            }
-        }
-
-        gen_match! {
-            Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot,
-            Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question,
-            Underscore;
-
-            Token::OpenDelim(delim) => quote!(::syntax::parse::token::OpenDelim((quote delim))),
-            Token::CloseDelim(delim) => quote!(::syntax::parse::token::CloseDelim((quote delim))),
-            Token::BinOp(tok) => quote!(::syntax::parse::token::BinOp((quote tok))),
-            Token::BinOpEq(tok) => quote!(::syntax::parse::token::BinOpEq((quote tok))),
-            Token::Ident(ident) => quote!(::syntax::parse::token::Ident((quote ident))),
-            Token::Lifetime(ident) => quote!(::syntax::parse::token::Lifetime((quote ident))),
-            Token::Literal(lit, sfx) => quote! {
-                ::syntax::parse::token::Literal((quote lit), (quote sfx))
-            },
-            _ => panic!("Unhandled case!"),
-        }
-    }
-}
-
-impl Quote for token::BinOpToken {
-    fn quote(&self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident),*) => {
-                match *self {
-                    $( token::BinOpToken::$i => quote!(::syntax::parse::token::BinOpToken::$i), )*
-                }
-            }
-        }
-
-        gen_match!(Plus, Minus, Star, Slash, Percent, Caret, And, Or, Shl, Shr)
-    }
-}
-
-impl Quote for Lit {
-    fn quote(&self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident),*; $($raw:ident),*) => {
-                match *self {
-                    $( Lit::$i(lit) => quote!(::syntax::parse::token::Lit::$i((quote lit))), )*
-                    $( Lit::$raw(lit, n) => {
-                        quote!(::syntax::parse::token::Lit::$raw((quote lit), (quote n)))
-                    })*
-                }
-            }
-        }
-
-        gen_match!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw)
-    }
-}
-
-impl Quote for token::DelimToken {
-    fn quote(&self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident),*) => {
-                match *self {
-                    $(token::DelimToken::$i => { quote!(::syntax::parse::token::DelimToken::$i) })*
-                }
-            }
-        }
-
-        gen_match!(Paren, Bracket, Brace, NoDelim)
-    }
-}
diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs
index 1ee284ff4dabf..55df14ea2150a 100644
--- a/src/libprofiler_builtins/build.rs
+++ b/src/libprofiler_builtins/build.rs
@@ -53,7 +53,7 @@ fn main() {
     }
 
     for src in profile_sources {
-        cfg.file(Path::new("../compiler-rt/lib/profile").join(src));
+        cfg.file(Path::new("../libcompiler_builtins/compiler-rt/lib/profile").join(src));
     }
 
     cfg.compile("libprofiler-rt.a");
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index ca05db15ffeb9..5e56b0d8ab16c 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -31,7 +31,7 @@
             issue = "27703")]
 #![feature(core_intrinsics)]
 #![feature(staged_api)]
-#![feature(step_by)]
+#![feature(iterator_step_by)]
 #![feature(custom_attribute)]
 #![feature(specialization)]
 #![allow(unused_attributes)]
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 85b1858c875bc..fa6b78045ffad 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -58,11 +58,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let tables = tcx.typeck_tables_of(owner_def_id);
 
     let mut cfg_builder = CFGBuilder {
-        tcx: tcx,
+        tcx,
         owner_def_id,
-        tables: tables,
-        graph: graph,
-        fn_exit: fn_exit,
+        tables,
+        graph,
+        fn_exit,
         loop_scopes: Vec::new(),
         breakable_block_scopes: Vec::new(),
     };
@@ -70,8 +70,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cfg_builder.add_contained_edge(body_exit, fn_exit);
     let CFGBuilder { graph, .. } = cfg_builder;
     CFG {
-        graph: graph,
-        entry: entry,
+        graph,
+        entry,
         exit: fn_exit,
     }
 }
diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs
index 43f8d6b938dab..ca53fd7a43311 100644
--- a/src/librustc/dep_graph/dep_tracking_map.rs
+++ b/src/librustc/dep_graph/dep_tracking_map.rs
@@ -36,7 +36,7 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
     pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
         DepTrackingMap {
             phantom: PhantomData,
-            graph: graph,
+            graph,
             map: FxHashMap(),
         }
     }
diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs
index 116c527bf46d5..283da1050aedc 100644
--- a/src/librustc/dep_graph/query.rs
+++ b/src/librustc/dep_graph/query.rs
@@ -36,8 +36,8 @@ impl DepGraphQuery {
         }
 
         DepGraphQuery {
-            graph: graph,
-            indices: indices
+            graph,
+            indices,
         }
     }
 
diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs
index 8808ea5948da8..e32acbf4756ca 100644
--- a/src/librustc/dep_graph/shadow.rs
+++ b/src/librustc/dep_graph/shadow.rs
@@ -59,7 +59,7 @@ impl ShadowGraph {
 
         ShadowGraph {
             stack: RefCell::new(vec![]),
-            forbidden_edge: forbidden_edge,
+            forbidden_edge,
         }
     }
 
diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs
index ad0abfe26f45f..f6635fe16f77d 100644
--- a/src/librustc/dep_graph/thread.rs
+++ b/src/librustc/dep_graph/thread.rs
@@ -78,7 +78,7 @@ impl DepGraphThreadData {
         }
 
         DepGraphThreadData {
-            enabled: enabled,
+            enabled,
             shadow_graph: ShadowGraph::new(),
             messages: VecCell::with_capacity(INITIAL_CAPACITY),
             swap_in: rx2,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 873d39ec9e9fb..a6a294343005c 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -126,9 +126,9 @@ pub fn lower_crate(sess: &Session,
 
     LoweringContext {
         crate_root: std_inject::injected_crate_name(krate),
-        sess: sess,
+        sess,
         parent_def: None,
-        resolver: resolver,
+        resolver,
         name_map: FxHashMap(),
         items: BTreeMap::new(),
         trait_items: BTreeMap::new(),
@@ -251,15 +251,15 @@ impl<'a> LoweringContext<'a> {
             .init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
 
         hir::Crate {
-            module: module,
-            attrs: attrs,
+            module,
+            attrs,
             span: c.span,
             exported_macros: hir::HirVec::from(self.exported_macros),
             items: self.items,
             trait_items: self.trait_items,
             impl_items: self.impl_items,
             bodies: self.bodies,
-            body_ids: body_ids,
+            body_ids,
             trait_impls: self.trait_impls,
             trait_default_impl: self.trait_default_impl,
         }
@@ -368,7 +368,7 @@ impl<'a> LoweringContext<'a> {
             arguments: decl.map_or(hir_vec![], |decl| {
                 decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
             }),
-            value: value
+            value,
         };
         let id = body.id();
         self.bodies.insert(id, body);
@@ -809,7 +809,7 @@ impl<'a> LoweringContext<'a> {
                 self.lower_path_segment(p.span, segment, param_mode, 0)
             }).chain(name.map(|name| {
                 hir::PathSegment {
-                    name: name,
+                    name,
                     parameters: hir::PathParameters::none()
                 }
             })).collect(),
@@ -857,7 +857,7 @@ impl<'a> LoweringContext<'a> {
 
         hir::PathSegment {
             name: self.lower_ident(segment.identifier),
-            parameters: parameters,
+            parameters,
         }
     }
 
@@ -881,7 +881,7 @@ impl<'a> LoweringContext<'a> {
         hir::ParenthesizedParameterData {
             inputs: inputs.iter().map(|ty| self.lower_ty(ty)).collect(),
             output: output.as_ref().map(|ty| self.lower_ty(ty)),
-            span: span,
+            span,
         }
     }
 
@@ -970,8 +970,8 @@ impl<'a> LoweringContext<'a> {
 
         hir::TyParam {
             id: self.lower_node_id(tp.id),
-            name: name,
-            bounds: bounds,
+            name,
+            bounds,
             default: tp.default.as_ref().map(|x| self.lower_ty(x)),
             span: tp.span,
             pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
@@ -1081,14 +1081,14 @@ impl<'a> LoweringContext<'a> {
                         TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
                         _ => Some(self.lower_ty_param_bound(bound))
                     }).collect(),
-                    span: span,
+                    span,
                 })
             }
             WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
                                                                   ref bounds,
                                                                   span}) => {
                 hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
-                    span: span,
+                    span,
                     lifetime: self.lower_lifetime(lifetime),
                     bounds: bounds.iter().map(|bound| self.lower_lifetime(bound)).collect(),
                 })
@@ -1101,7 +1101,7 @@ impl<'a> LoweringContext<'a> {
                     id: self.lower_node_id(id),
                     lhs_ty: self.lower_ty(lhs_ty),
                     rhs_ty: self.lower_ty(rhs_ty),
-                    span: span,
+                    span,
                 })
             }
         }
@@ -1133,7 +1133,7 @@ impl<'a> LoweringContext<'a> {
             qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath)
         };
         hir::TraitRef {
-            path: path,
+            path,
             ref_id: self.lower_node_id(p.ref_id),
         }
     }
@@ -1201,10 +1201,10 @@ impl<'a> LoweringContext<'a> {
         P(hir::Block {
             id: self.lower_node_id(b.id),
             stmts: stmts.into(),
-            expr: expr,
+            expr,
             rules: self.lower_block_check_mode(&b.rules),
             span: b.span,
-            targeted_by_break: targeted_by_break,
+            targeted_by_break,
         })
     }
 
@@ -1259,8 +1259,8 @@ impl<'a> LoweringContext<'a> {
                                     name: import.rename.unwrap_or(ident).name,
                                     attrs: attrs.clone(),
                                     node: hir::ItemUse(P(path), hir::UseKind::Single),
-                                    vis: vis,
-                                    span: span,
+                                    vis,
+                                    span,
                                 });
                             });
                         }
@@ -1441,7 +1441,7 @@ impl<'a> LoweringContext<'a> {
             name: self.lower_ident(i.ident),
             span: i.span,
             defaultness: self.lower_defaultness(Defaultness::Default, has_default),
-            kind: kind,
+            kind,
         }
     }
 
@@ -1523,9 +1523,9 @@ impl<'a> LoweringContext<'a> {
         if let ItemKind::MacroDef(ref def) = i.node {
             if !def.legacy || i.attrs.iter().any(|attr| attr.path == "macro_export") {
                 self.exported_macros.push(hir::MacroDef {
-                    name: name,
-                    vis: vis,
-                    attrs: attrs,
+                    name,
+                    vis,
+                    attrs,
                     id: i.id,
                     span: i.span,
                     body: def.stream(),
@@ -1541,10 +1541,10 @@ impl<'a> LoweringContext<'a> {
 
         Some(hir::Item {
             id: self.lower_node_id(i.id),
-            name: name,
-            attrs: attrs,
-            node: node,
-            vis: vis,
+            name,
+            attrs,
+            node,
+            vis,
             span: i.span,
         })
     }
@@ -1650,7 +1650,7 @@ impl<'a> LoweringContext<'a> {
                             Some(def) => {
                                 hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
                                     span: pth1.span,
-                                    def: def,
+                                    def,
                                     segments: hir_vec![
                                         hir::PathSegment::from_name(pth1.node.name)
                                     ],
@@ -1887,9 +1887,9 @@ impl<'a> LoweringContext<'a> {
                             let blk = P(hir::Block {
                                 stmts: hir_vec![],
                                 expr: Some(els),
-                                id: id,
+                                id,
                                 rules: hir::DefaultBlock,
-                                span: span,
+                                span,
                                 targeted_by_break: false,
                             });
                             P(self.expr_block(blk, ThinVec::new()))
@@ -2108,7 +2108,7 @@ impl<'a> LoweringContext<'a> {
                     sub_expr,
                     arms.into(),
                     hir::MatchSource::IfLetDesugar {
-                        contains_else_clause: contains_else_clause,
+                        contains_else_clause,
                     })
             }
 
@@ -2536,7 +2536,7 @@ impl<'a> LoweringContext<'a> {
     fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
         hir::Arm {
             attrs: hir_vec![],
-            pats: pats,
+            pats,
             guard: None,
             body: expr,
         }
@@ -2546,10 +2546,10 @@ impl<'a> LoweringContext<'a> {
         hir::Field {
             name: Spanned {
                 node: name,
-                span: span,
+                span,
             },
-            span: span,
-            expr: expr,
+            span,
+            expr,
             is_shorthand: false,
         }
     }
@@ -2578,8 +2578,8 @@ impl<'a> LoweringContext<'a> {
         };
 
         let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path {
-            span: span,
-            def: def,
+            span,
+            def,
             segments: hir_vec![hir::PathSegment::from_name(id)],
         })));
 
@@ -2619,9 +2619,9 @@ impl<'a> LoweringContext<'a> {
     fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> hir::Expr {
         hir::Expr {
             id: self.next_id(),
-            node: node,
-            span: span,
-            attrs: attrs,
+            node,
+            span,
+            attrs,
         }
     }
 
@@ -2632,7 +2632,7 @@ impl<'a> LoweringContext<'a> {
                     source: hir::LocalSource)
                     -> hir::Stmt {
         let local = P(hir::Local {
-            pat: pat,
+            pat,
             ty: None,
             init: ex,
             id: self.next_id(),
@@ -2662,11 +2662,11 @@ impl<'a> LoweringContext<'a> {
     fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<P<hir::Expr>>)
                  -> hir::Block {
         hir::Block {
-            stmts: stmts,
-            expr: expr,
+            stmts,
+            expr,
             id: self.next_id(),
             rules: hir::DefaultBlock,
-            span: span,
+            span,
             targeted_by_break: false,
         }
     }
@@ -2719,15 +2719,15 @@ impl<'a> LoweringContext<'a> {
         };
 
         P(hir::Pat {
-            id: id,
+            id,
             node: hir::PatKind::Binding(bm,
                                         def_id,
                                         Spanned {
-                                            span: span,
+                                            span,
                                             node: name,
                                         },
                                         None),
-            span: span,
+            span,
         })
     }
 
@@ -2739,7 +2739,7 @@ impl<'a> LoweringContext<'a> {
         P(hir::Pat {
             id: self.next_id(),
             node: pat,
-            span: span,
+            span,
         })
     }
 
@@ -2748,7 +2748,7 @@ impl<'a> LoweringContext<'a> {
     /// The path is also resolved according to `is_value`.
     fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
         let mut path = hir::Path {
-            span: span,
+            span,
             def: Def::Err,
             segments: iter::once(keywords::CrateRoot.name()).chain({
                 self.crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern)
@@ -2769,9 +2769,9 @@ impl<'a> LoweringContext<'a> {
         let id = self.next_id();
         let block = P(hir::Block {
             rules: rule,
-            span: span,
-            id: id,
-            stmts: stmts,
+            span,
+            id,
+            stmts,
             expr: Some(expr),
             targeted_by_break: false,
         });
@@ -2810,7 +2810,7 @@ impl<'a> LoweringContext<'a> {
     fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
         hir::Lifetime {
             id: self.next_id(),
-            span: span,
+            span,
             name: keywords::Invalid.name()
         }
     }
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index ff2f1dc1ba28a..661798a825056 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -130,9 +130,9 @@ impl<'a> ClosureParts<'a> {
         ClosureParts {
             decl: d,
             body: b,
-            id: id,
+            id,
             span: s,
-            attrs: attrs,
+            attrs,
         }
     }
 }
@@ -149,7 +149,7 @@ impl<'a> FnLikeNode<'a> {
         };
         if fn_like {
             Some(FnLikeNode {
-                node: node
+                node,
             })
         } else {
             None
@@ -224,12 +224,12 @@ impl<'a> FnLikeNode<'a> {
                         id: i.id,
                         name: i.name,
                         decl: &decl,
-                        unsafety: unsafety,
+                        unsafety,
                         body: block,
-                        generics: generics,
-                        abi: abi,
+                        generics,
+                        abi,
                         vis: &i.vis,
-                        constness: constness,
+                        constness,
                         span: i.span,
                         attrs: &i.attrs,
                     }),
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 904f74b8787fd..d3ae3e0e8e8ac 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -28,7 +28,7 @@ pub struct NodeCollector<'hir> {
 impl<'hir> NodeCollector<'hir> {
     pub fn root(krate: &'hir Crate) -> NodeCollector<'hir> {
         let mut collector = NodeCollector {
-            krate: krate,
+            krate,
             map: vec![],
             parent_node: CRATE_NODE_ID,
         };
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 7fbefa5788b26..d348a5db05170 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -36,8 +36,8 @@ pub struct MacroInvocationData {
 impl<'a> DefCollector<'a> {
     pub fn new(definitions: &'a mut Definitions, expansion: Mark) -> Self {
         DefCollector {
-            definitions: definitions,
-            expansion: expansion,
+            definitions,
+            expansion,
             parent_def: None,
             visit_macro_invoc: None,
         }
@@ -86,7 +86,7 @@ impl<'a> DefCollector<'a> {
         if let Some(ref mut visit) = self.visit_macro_invoc {
             visit(MacroInvocationData {
                 mark: id.placeholder_to_mark(),
-                const_expr: const_expr,
+                const_expr,
                 def_index: self.parent_def.unwrap(),
             })
         }
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index c969aef675ff9..d89e86ee66a66 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -190,9 +190,9 @@ impl Decodable for DefPathTable {
         }
 
         Ok(DefPathTable {
-            index_to_key: index_to_key,
-            key_to_index: key_to_index,
-            def_path_hashes: def_path_hashes,
+            index_to_key,
+            key_to_index,
+            def_path_hashes,
         })
     }
 }
@@ -578,7 +578,7 @@ impl Definitions {
         let mut key = DefKey {
             parent: Some(parent),
             disambiguated_data: DisambiguatedDefPathData {
-                data: data,
+                data,
                 disambiguator: 0
             }
         };
diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs
index b3cc0c542ef9d..e6af075a2985f 100644
--- a/src/librustc/hir/map/hir_id_validator.rs
+++ b/src/librustc/hir/map/hir_id_validator.rs
@@ -16,7 +16,7 @@ use rustc_data_structures::fx::FxHashMap;
 
 pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) {
     let mut outer_visitor = OuterVisitor {
-        hir_map: hir_map,
+        hir_map,
         errors: vec![],
     };
 
@@ -49,7 +49,7 @@ impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> {
                          hir_map: &'a hir::map::Map<'hir>)
                          -> HirIdValidator<'a, 'hir> {
         HirIdValidator {
-            hir_map: hir_map,
+            hir_map,
             owner_def_index: None,
             hir_ids_seen: FxHashMap(),
             errors: Vec::new(),
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 02a36a372d9ef..2044d32ff9b85 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -228,7 +228,7 @@ pub struct Forest {
 impl Forest {
     pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest {
         Forest {
-            krate: krate,
+            krate,
             dep_graph: dep_graph.clone(),
             inlined_bodies: TypedArena::new()
         }
@@ -1057,10 +1057,10 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest,
     }
 
     let map = Map {
-        forest: forest,
+        forest,
         dep_graph: forest.dep_graph.clone(),
-        map: map,
-        definitions: definitions,
+        map,
+        definitions,
         inlined_bodies: RefCell::new(DefIdMap()),
     };
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 3f2977cc503df..3443c6bb2c659 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -218,7 +218,7 @@ impl PathSegment {
     /// Convert an identifier to the corresponding segment.
     pub fn from_name(name: Name) -> PathSegment {
         PathSegment {
-            name: name,
+            name,
             parameters: PathParameters::none()
         }
     }
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index c6f4cd585d7b5..f32fab7d847d7 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -176,7 +176,7 @@ impl<'a> State<'a> {
                 cur_lit: 0,
             },
             boxes: Vec::new(),
-            ann: ann,
+            ann,
         }
     }
 }
@@ -196,7 +196,7 @@ pub fn to_string<F>(ann: &PpAnn, f: F) -> String
                 cur_lit: 0,
             },
             boxes: Vec::new(),
-            ann: ann,
+            ann,
         };
         f(&mut printer).unwrap();
         eof(&mut printer.s).unwrap();
diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs
index bf47b9bb9d43d..49e18f100cf26 100644
--- a/src/librustc/ich/caching_codemap_view.rs
+++ b/src/librustc/ich/caching_codemap_view.rs
@@ -44,7 +44,7 @@ impl<'gcx> CachingCodemapView<'gcx> {
         };
 
         CachingCodemapView {
-            codemap: codemap,
+            codemap,
             line_cache: [entry.clone(), entry.clone(), entry.clone()],
             time_stamp: 0,
         }
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 2784a7bd024f6..8ce1b39d934d1 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -65,13 +65,13 @@ impl<'a, 'gcx, 'tcx> StableHashingContext<'a, 'gcx, 'tcx> {
         ignored_attr_names.sort();
 
         StableHashingContext {
-            tcx: tcx,
+            tcx,
             codemap: CachingCodemapView::new(tcx),
             hash_spans: hash_spans_initial,
             hash_bodies: true,
             overflow_checks_enabled: check_overflow_initial,
             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
-            ignored_attr_names: ignored_attr_names,
+            ignored_attr_names,
         }
     }
 
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index b9cc3b5fb937f..b827284271ed2 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -283,8 +283,7 @@ fn hash_token<'a, 'gcx, 'tcx, W: StableHasherResult>(token: &token::Token,
         }
 
         token::Token::Ident(ident) |
-        token::Token::Lifetime(ident) |
-        token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher),
+        token::Token::Lifetime(ident) => ident.name.hash_stable(hcx, hasher),
 
         token::Token::Interpolated(ref non_terminal) => {
             // FIXME(mw): This could be implemented properly. It's just a
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 14920b8b668ec..40e933b26a257 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -268,7 +268,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
             infcx: self.infcx,
             span: self.trace.cause.span,
             for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
-            ambient_variance: ambient_variance,
+            ambient_variance,
             needs_wf: false,
         };
 
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index a0ef1f65f52ea..41858088f7e70 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -48,7 +48,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
     pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
                -> TypeFreshener<'a, 'gcx, 'tcx> {
         TypeFreshener {
-            infcx: infcx,
+            infcx,
             freshen_count: 0,
             freshen_map: FxHashMap(),
         }
diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs
index a8bc33f772d55..9cad6ce6f9fad 100644
--- a/src/librustc/infer/fudge.rs
+++ b/src/librustc/infer/fudge.rs
@@ -102,7 +102,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             infcx: self,
             type_variables: &type_variables,
             region_vars: &region_vars,
-            origin: origin
+            origin,
         };
 
         Ok(value.fold_with(&mut fudger))
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index dbbcc6cfbec6b..541a9978341f6 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
             Ok(HrMatchResult {
                 value: a_value,
-                unconstrained_regions: unconstrained_regions,
+                unconstrained_regions,
             })
         });
     }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 5cb1606da6708..a70a4248cb75b 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -458,9 +458,9 @@ impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
             LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx, param_env) },
             LvalueTy::Downcast { adt_def, substs, variant_index } => {
                 LvalueTy::Downcast {
-                    adt_def: adt_def,
+                    adt_def,
                     substs: substs.trans_normalize(infcx, param_env),
-                    variant_index: variant_index
+                    variant_index,
                 }
             }
         }
@@ -674,7 +674,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                       -> CombineFields<'a, 'gcx, 'tcx> {
         CombineFields {
             infcx: self,
-            trace: trace,
+            trace,
             cause: None,
             param_env,
             obligations: PredicateObligations::new(),
@@ -1235,7 +1235,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.report_and_explain_type_error(
             trace,
             &TypeError::TyParamDefaultMismatch(ExpectedFound {
-                expected: expected,
+                expected,
                 found: actual
             }))
             .emit();
@@ -1279,7 +1279,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let span = cause.span;
         let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref;
         let trace = TypeTrace {
-            cause: cause,
+            cause,
             values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b))
         };
 
@@ -1443,10 +1443,10 @@ impl<'tcx> SubregionOrigin<'tcx> {
                                                                        lint_id } =>
                 SubregionOrigin::CompareImplMethodObligation {
                     span: cause.span,
-                    item_name: item_name,
-                    impl_item_def_id: impl_item_def_id,
-                    trait_item_def_id: trait_item_def_id,
-                    lint_id: lint_id,
+                    item_name,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                    lint_id,
                 },
 
             _ => default(),
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 6f88b97334cef..4f8168982496e 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -354,7 +354,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
 impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> RegionVarBindings<'a, 'gcx, 'tcx> {
         RegionVarBindings {
-            tcx: tcx,
+            tcx,
             var_origins: RefCell::new(Vec::new()),
             values: RefCell::new(None),
             constraints: RefCell::new(FxHashMap()),
@@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         debug!("RegionVarBindings: start_snapshot({})", length);
         self.undo_log.borrow_mut().push(OpenSnapshot);
         RegionSnapshot {
-            length: length,
+            length,
             region_snapshot: self.unification_table.borrow_mut().snapshot(),
             skolemization_count: self.skolemization_count.get(),
         }
@@ -733,10 +733,10 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                                 sub: Region<'tcx>,
                                 bound: VerifyBound<'tcx>) {
         self.add_verify(Verify {
-            kind: kind,
-            origin: origin,
+            kind,
+            origin,
             region: sub,
-            bound: bound
+            bound,
         });
     }
 
@@ -1459,7 +1459,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                     ConstrainRegSubVar(region, _) |
                     ConstrainVarSubReg(_, region) => {
                         state.result.push(RegionAndOrigin {
-                            region: region,
+                            region,
                             origin: this.constraints.borrow().get(&edge.data).unwrap().clone(),
                         });
                     }
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 4ae2a8026409d..cc91a637b8931 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -181,8 +181,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
         self.sub_relations.new_key(());
         let index = self.values.push(TypeVariableData {
             value: Bounded { default: default },
-            origin: origin,
-            diverging: diverging
+            origin,
+            diverging,
         });
         let v = ty::TyVid { index: index as u32 };
         debug!("new_var: diverging={:?} index={:?}", diverging, v);
@@ -369,7 +369,7 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
     fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) {
         let Instantiate { vid, default } = action;
         values[vid.index as usize].value = Bounded {
-            default: default
+            default,
         };
     }
 }
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index e4cf893375c75..efa6a6cccc2b6 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -84,6 +84,7 @@ pub mod infer;
 pub mod lint;
 
 pub mod middle {
+    pub mod allocator;
     pub mod expr_use_visitor;
     pub mod const_val;
     pub mod cstore;
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 8202c6106d147..d67bca1df3022 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -140,8 +140,8 @@ impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) {
         let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg);
         diagnostic.set_span(span);
         EarlyLint {
-            id: id,
-            diagnostic: diagnostic,
+            id,
+            diagnostic,
         }
     }
 }
@@ -149,7 +149,7 @@ impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) {
 impl IntoEarlyLint for Diagnostic {
     fn into_early_lint(self, id: LintId) -> EarlyLint {
         EarlyLint {
-            id: id,
+            id,
             diagnostic: self,
         }
     }
@@ -805,8 +805,8 @@ impl<'a> EarlyContext<'a> {
     fn new(sess: &'a Session,
            krate: &'a ast::Crate) -> EarlyContext<'a> {
         EarlyContext {
-            sess: sess,
-            krate: krate,
+            sess,
+            krate,
             lint_sess: LintSession::new(&sess.lint_store),
         }
     }
@@ -1350,10 +1350,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let krate = tcx.hir.krate();
 
     let mut cx = LateContext {
-        tcx: tcx,
+        tcx,
         tables: &ty::TypeckTables::empty(),
         param_env: ty::ParamEnv::empty(Reveal::UserFacing),
-        access_levels: access_levels,
+        access_levels,
         lint_sess: LintSession::new(&tcx.sess.lint_store),
     };
 
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index e81d09773701c..f9222ac9400af 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -294,7 +294,7 @@ impl LintId {
     /// Get the `LintId` for a `Lint`.
     pub fn of(lint: &'static Lint) -> LintId {
         LintId {
-            lint: lint,
+            lint,
         }
     }
 
diff --git a/src/librustc/middle/allocator.rs b/src/librustc/middle/allocator.rs
new file mode 100644
index 0000000000000..79a9ef0e8b577
--- /dev/null
+++ b/src/librustc/middle/allocator.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#[derive(Clone, Copy)]
+pub enum AllocatorKind {
+    Global,
+    DefaultLib,
+    DefaultExe,
+}
+
+impl AllocatorKind {
+    pub fn fn_name(&self, base: &str) -> String {
+        match *self {
+            AllocatorKind::Global => format!("__rg_{}", base),
+            AllocatorKind::DefaultLib => format!("__rdl_{}", base),
+            AllocatorKind::DefaultExe => format!("__rde_{}", base),
+        }
+    }
+}
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 7d62103e386c4..42f4c5c59d994 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -260,16 +260,16 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         let nodeid_to_index = build_nodeid_to_index(body, cfg);
 
         DataFlowContext {
-            tcx: tcx,
-            analysis_name: analysis_name,
-            words_per_id: words_per_id,
-            nodeid_to_index: nodeid_to_index,
-            bits_per_id: bits_per_id,
-            oper: oper,
-            gens: gens,
+            tcx,
+            analysis_name,
+            words_per_id,
+            nodeid_to_index,
+            bits_per_id,
+            oper,
+            gens,
             action_kills: kills1,
             scope_kills: kills2,
-            on_entry: on_entry
+            on_entry,
         }
     }
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 6077b7863e2c3..2238e464cbcd5 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -287,6 +287,11 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
         return true;
     }
 
+    // Don't lint about global allocators
+    if attr::contains_name(attrs, "global_allocator") {
+        return true;
+    }
+
     let dead_code = lint::builtin::DEAD_CODE.name_lower();
     for attr in lint::gather_attrs(attrs) {
         match attr {
@@ -378,8 +383,8 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Seed implemented trait items
     let mut life_seeder = LifeSeeder {
-        worklist: worklist,
-        krate: krate,
+        worklist,
+        krate,
     };
     krate.visit_all_item_likes(&mut life_seeder);
 
@@ -392,8 +397,8 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                        -> Box<FxHashSet<ast::NodeId>> {
     let worklist = create_and_seed_worklist(tcx, access_levels, krate);
     let mut symbol_visitor = MarkSymbolVisitor {
-        worklist: worklist,
-        tcx: tcx,
+        worklist,
+        tcx,
         tables: &ty::TypeckTables::empty(),
         live_symbols: box FxHashSet(),
         struct_has_extern_repr: false,
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index 4e1f06cca06cc..9af93d0d49424 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -214,10 +214,9 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     //
     // Things like allocators and panic runtimes may not have been activated
     // quite yet, so do so here.
-    activate_injected_dep(sess.injected_allocator.get(), &mut ret,
-                          &|cnum| tcx.is_allocator(cnum.as_def_id()));
     activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
                           &|cnum| tcx.is_panic_runtime(cnum.as_def_id()));
+    activate_injected_allocator(sess, &mut ret);
 
     // When dylib B links to dylib A, then when using B we must also link to A.
     // It could be the case, however, that the rlib for A is present (hence we
@@ -295,10 +294,9 @@ fn attempt_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<DependencyLis
     // Our allocator/panic runtime may not have been linked above if it wasn't
     // explicitly linked, which is the case for any injected dependency. Handle
     // that here and activate them.
-    activate_injected_dep(sess.injected_allocator.get(), &mut ret,
-                          &|cnum| tcx.is_allocator(cnum.as_def_id()));
     activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
                           &|cnum| tcx.is_panic_runtime(cnum.as_def_id()));
+    activate_injected_allocator(sess, &mut ret);
 
     Some(ret)
 }
@@ -331,6 +329,18 @@ fn activate_injected_dep(injected: Option<CrateNum>,
     }
 }
 
+fn activate_injected_allocator(sess: &session::Session,
+                               list: &mut DependencyList) {
+    let cnum = match sess.injected_allocator.get() {
+        Some(cnum) => cnum,
+        None => return,
+    };
+    let idx = cnum.as_usize() - 1;
+    if list[idx] == Linkage::NotLinked {
+        list[idx] = Linkage::Static;
+    }
+}
+
 // After the linkage for a crate has been determined we need to verify that
 // there's only going to be one allocator in the output.
 fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) {
@@ -338,23 +348,12 @@ fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) {
     if list.len() == 0 {
         return
     }
-    let mut allocator = None;
     let mut panic_runtime = None;
     for (i, linkage) in list.iter().enumerate() {
         if let Linkage::NotLinked = *linkage {
             continue
         }
         let cnum = CrateNum::new(i + 1);
-        if tcx.is_allocator(cnum.as_def_id()) {
-            if let Some(prev) = allocator {
-                let prev_name = sess.cstore.crate_name(prev);
-                let cur_name = sess.cstore.crate_name(cnum);
-                sess.err(&format!("cannot link together two \
-                                   allocators: {} and {}",
-                                  prev_name, cur_name));
-            }
-            allocator = Some(cnum);
-        }
 
         if tcx.is_panic_runtime(cnum.as_def_id()) {
             if let Some((prev, _)) = panic_runtime {
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index eab5a8f910331..abd5cbcb89e33 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -261,7 +261,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut visitor = EffectCheckVisitor {
-        tcx: tcx,
+        tcx,
         tables: &ty::TypeckTables::empty(),
         body_id: hir::BodyId { node_id: ast::CRATE_NODE_ID },
         unsafe_context: UnsafeContext::new(SafeContext),
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index b26cccf5f1617..31e054ec1cb93 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -71,7 +71,7 @@ pub fn find_entry_point(session: &Session, hir_map: &hir_map::Map) {
     }
 
     let mut ctxt = EntryContext {
-        session: session,
+        session,
         map: hir_map,
         main_fn: None,
         attr_main_fn: None,
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index fde207e4b2f79..d29622b4a8159 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -20,7 +20,7 @@ use hir;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut visitor = ItemVisitor {
-        tcx: tcx
+        tcx,
     };
     tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 3b506d748ef7a..01ed79096b101 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -156,10 +156,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
         $( item_refs.insert($name, $variant as usize); )*
 
         LanguageItemCollector {
-            session: session,
-            hir_map: hir_map,
+            session,
+            hir_map,
             items: LanguageItems::new(),
-            item_refs: item_refs,
+            item_refs,
         }
     }
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index c6a42be6135cc..551a550442b3d 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -269,7 +269,7 @@ struct IrMaps<'a, 'tcx: 'a> {
 impl<'a, 'tcx> IrMaps<'a, 'tcx> {
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IrMaps<'a, 'tcx> {
         IrMaps {
-            tcx: tcx,
+            tcx,
             num_live_nodes: 0,
             num_vars: 0,
             live_node_map: NodeMap(),
@@ -385,7 +385,7 @@ fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
         ir.add_live_node_for_node(p_id, VarDefNode(sp));
         ir.add_variable(Local(LocalInfo {
           id: p_id,
-          name: name
+          name,
         }));
     });
     intravisit::walk_local(ir, local);
@@ -400,7 +400,7 @@ fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) {
             ir.add_live_node_for_node(p_id, VarDefNode(sp));
             ir.add_variable(Local(LocalInfo {
                 id: p_id,
-                name: name
+                name,
             }));
         })
     }
@@ -534,8 +534,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         let num_vars = ir.num_vars;
 
         Liveness {
-            ir: ir,
-            tables: tables,
+            ir,
+            tables,
             s: specials,
             successors: vec![invalid_node(); num_live_nodes],
             users: vec![invalid_users(); num_live_nodes * num_vars],
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 5c741eccf83c7..557d4b24f3032 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -656,8 +656,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
           Def::Local(def_id) => {
             let vid = self.tcx.hir.as_local_node_id(def_id).unwrap();
             Ok(Rc::new(cmt_ {
-                id: id,
-                span: span,
+                id,
+                span,
                 cat: Categorization::Local(vid),
                 mutbl: MutabilityCategory::from_local(self.tcx, vid),
                 ty: expr_ty,
@@ -706,7 +706,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             None => span_bug!(span, "missing closure kind")
         };
 
-        let upvar_id = ty::UpvarId { var_id: var_id,
+        let upvar_id = ty::UpvarId { var_id,
                                      closure_expr_id: fn_node_id };
         let var_ty = self.node_ty(var_id)?;
 
@@ -717,8 +717,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // from the environment (perhaps we should eventually desugar
         // this field further, but it will do for now).
         let cmt_result = cmt_ {
-            id: id,
-            span: span,
+            id,
+            span,
             cat: Categorization::Upvar(Upvar {id: upvar_id, kind: kind}),
             mutbl: var_mutbl,
             ty: var_ty,
@@ -743,7 +743,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // If this is a by-ref capture, then the upvar we loaded is
         // actually a reference, so we have to add an implicit deref
         // for that.
-        let upvar_id = ty::UpvarId { var_id: var_id,
+        let upvar_id = ty::UpvarId { var_id,
                                      closure_expr_id: fn_node_id };
         let upvar_capture = self.tables.upvar_capture(upvar_id);
         let cmt_result = match upvar_capture {
@@ -753,8 +753,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             ty::UpvarCapture::ByRef(upvar_borrow) => {
                 let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
                 cmt_ {
-                    id: id,
-                    span: span,
+                    id,
+                    span,
                     cat: Categorization::Deref(Rc::new(cmt_result), ptr),
                     mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
                     ty: var_ty,
@@ -813,8 +813,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         }
 
         let ret = cmt_ {
-            id: id,
-            span: span,
+            id,
+            span,
             cat: Categorization::Deref(Rc::new(cmt_result), env_ptr),
             mutbl: deref_mutbl,
             ty: var_ty,
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index c2f69147e3a56..df828c8d8e71a 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -374,11 +374,11 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) ->
         *ty == config::CrateTypeProcMacro
     });
     let mut reachable_context = ReachableContext {
-        tcx: tcx,
+        tcx,
         tables: &ty::TypeckTables::empty(),
         reachable_symbols: NodeSet(),
         worklist: Vec::new(),
-        any_library: any_library,
+        any_library,
     };
 
     // Step 1: Seed the worklist with all nodes which were found to be public as
@@ -398,8 +398,8 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) ->
     }
     {
         let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
-            tcx: tcx,
-            access_levels: access_levels,
+            tcx,
+            access_levels,
             worklist: &mut reachable_context.worklist,
         };
         tcx.hir.krate().visit_all_item_likes(&mut collect_private_impl_items);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index b347a93185124..c4f785757cee1 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -266,8 +266,8 @@ pub fn krate(sess: &Session,
     };
     sess.track_errors(|| {
         let mut visitor = LifetimeContext {
-            sess: sess,
-            hir_map: hir_map,
+            sess,
+            hir_map,
             map: &mut map,
             scope: ROOT_SCOPE,
             trait_ref_hack: false,
@@ -341,7 +341,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     Region::early(&mut index, def)
                 }).collect();
                 let scope = Scope::Binder {
-                    lifetimes: lifetimes,
+                    lifetimes,
                     s: ROOT_SCOPE
                 };
                 self.with(scope, |old_scope, this| {
@@ -777,13 +777,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let xcrate_object_lifetime_defaults =
             replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
         let mut this = LifetimeContext {
-            sess: sess,
-            hir_map: hir_map,
+            sess,
+            hir_map,
             map: *map,
             scope: &wrap_scope,
             trait_ref_hack: self.trait_ref_hack,
-            labels_in_fn: labels_in_fn,
-            xcrate_object_lifetime_defaults: xcrate_object_lifetime_defaults,
+            labels_in_fn,
+            xcrate_object_lifetime_defaults,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
@@ -849,7 +849,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }).collect();
 
         let scope = Scope::Binder {
-            lifetimes: lifetimes,
+            lifetimes,
             s: self.scope
         };
         self.with(scope, move |old_scope, this| {
@@ -1206,7 +1206,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         };
 
         let scope = Scope::Elision {
-            elide: elide,
+            elide,
             s: self.scope
         };
         self.with(scope, |_, this| this.visit_ty(output));
@@ -1620,7 +1620,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
             map.issue_32330.insert(
                 lifetime.lifetime.id,
                 ty::Issue32330 {
-                    fn_def_id: fn_def_id,
+                    fn_def_id,
                     region_name: name,
                 });
             continue;
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e27990c29cf9e..668a8693d3a84 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -70,14 +70,14 @@ impl DeprecationEntry {
     fn local(attr: Deprecation, id: DefId) -> DeprecationEntry {
         assert!(id.is_local());
         DeprecationEntry {
-            attr: attr,
+            attr,
             origin: Some(id.index),
         }
     }
 
     fn external(attr: Deprecation) -> DeprecationEntry {
         DeprecationEntry {
-            attr: attr,
+            attr,
             origin: None,
         }
     }
@@ -384,7 +384,7 @@ impl<'a, 'tcx> Index<'tcx> {
 
         let krate = tcx.hir.krate();
         let mut annotator = Annotator {
-            tcx: tcx,
+            tcx,
             index: self,
             parent_stab: None,
             parent_depr: None,
@@ -424,7 +424,7 @@ impl<'a, 'tcx> Index<'tcx> {
         let mut staged_api = FxHashMap();
         staged_api.insert(LOCAL_CRATE, is_staged_api);
         Index {
-            staged_api: staged_api,
+            staged_api,
             stab_map: DefIdMap(),
             depr_map: DefIdMap(),
             active_features: FxHashSet(),
@@ -717,8 +717,8 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     if tcx.stability.borrow().staged_api[&LOCAL_CRATE] {
         let krate = tcx.hir.krate();
         let mut missing = MissingStabilityAnnotations {
-            tcx: tcx,
-            access_levels: access_levels,
+            tcx,
+            access_levels,
         };
         missing.check_missing_stability(ast::CRATE_NODE_ID, krate.span);
         intravisit::walk_crate(&mut missing, krate);
@@ -728,6 +728,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let ref declared_lib_features = sess.features.borrow().declared_lib_features;
     let mut remaining_lib_features: FxHashMap<Symbol, Span>
         = declared_lib_features.clone().into_iter().collect();
+    remaining_lib_features.remove(&Symbol::intern("proc_macro"));
 
     fn format_stable_since_msg(version: &str) -> String {
         format!("this feature has been stable since {}. Attribute no longer needed", version)
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index c8d03e7b30588..96ccc3ba50078 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -136,15 +136,15 @@ impl<'tcx> Mir<'tcx> {
         assert_eq!(local_decls[RETURN_POINTER].ty, return_ty);
 
         Mir {
-            basic_blocks: basic_blocks,
-            visibility_scopes: visibility_scopes,
-            promoted: promoted,
-            return_ty: return_ty,
-            local_decls: local_decls,
-            arg_count: arg_count,
-            upvar_decls: upvar_decls,
+            basic_blocks,
+            visibility_scopes,
+            promoted,
+            return_ty,
+            local_decls,
+            arg_count,
+            upvar_decls,
             spread_arg: None,
-            span: span,
+            span,
             cache: cache::Cache::new()
         }
     }
@@ -395,10 +395,10 @@ impl<'tcx> LocalDecl<'tcx> {
     pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
         LocalDecl {
             mutability: Mutability::Mut,
-            ty: ty,
+            ty,
             name: None,
             source_info: SourceInfo {
-                span: span,
+                span,
                 scope: ARGUMENT_VISIBILITY_SCOPE
             },
             is_user_variable: false
@@ -414,7 +414,7 @@ impl<'tcx> LocalDecl<'tcx> {
             mutability: Mutability::Mut,
             ty: return_ty,
             source_info: SourceInfo {
-                span: span,
+                span,
                 scope: ARGUMENT_VISIBILITY_SCOPE
             },
             name: None,     // FIXME maybe we do want some name here?
@@ -629,7 +629,7 @@ impl<'tcx> BasicBlockData<'tcx> {
     pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
         BasicBlockData {
             statements: vec![],
-            terminator: terminator,
+            terminator,
             is_cleanup: false,
         }
     }
@@ -941,7 +941,7 @@ impl<'tcx> Lvalue<'tcx> {
     pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> {
         Lvalue::Projection(Box::new(LvalueProjection {
             base: self,
-            elem: elem,
+            elem,
         }))
     }
 }
@@ -1023,7 +1023,7 @@ impl<'tcx> Operand<'tcx> {
         span: Span,
     ) -> Self {
         Operand::Constant(box Constant {
-            span: span,
+            span,
             ty: tcx.type_of(def_id).subst(tcx, substs),
             literal: Literal::Value { value: ConstVal::Function(def_id, substs) },
         })
@@ -1470,7 +1470,7 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
             Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)),
             SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant {
                 lvalue: lvalue.fold_with(folder),
-                variant_index: variant_index
+                variant_index,
             },
             StorageLive(ref lval) => StorageLive(lval.fold_with(folder)),
             StorageDead(ref lval) => StorageDead(lval.fold_with(folder)),
@@ -1490,7 +1490,7 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
         };
         Statement {
             source_info: self.source_info,
-            kind: kind
+            kind,
         }
     }
 
@@ -1530,14 +1530,14 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
             },
             Drop { ref location, target, unwind } => Drop {
                 location: location.fold_with(folder),
-                target: target,
-                unwind: unwind
+                target,
+                unwind,
             },
             DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
                 location: location.fold_with(folder),
                 value: value.fold_with(folder),
-                target: target,
-                unwind: unwind
+                target,
+                unwind,
             },
             Call { ref func, ref args, ref destination, cleanup } => {
                 let dest = destination.as_ref().map(|&(ref loc, dest)| {
@@ -1548,7 +1548,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                     func: func.fold_with(folder),
                     args: args.fold_with(folder),
                     destination: dest,
-                    cleanup: cleanup
+                    cleanup,
                 }
             },
             Assert { ref cond, expected, ref msg, target, cleanup } => {
@@ -1562,10 +1562,10 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 };
                 Assert {
                     cond: cond.fold_with(folder),
-                    expected: expected,
-                    msg: msg,
-                    target: target,
-                    cleanup: cleanup
+                    expected,
+                    msg,
+                    target,
+                    cleanup,
                 }
             },
             Resume => Resume,
@@ -1574,7 +1574,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
         };
         Terminator {
             source_info: self.source_info,
-            kind: kind
+            kind,
         }
     }
 
@@ -1716,8 +1716,8 @@ impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V>
         };
 
         Projection {
-            base: base,
-            elem: elem
+            base,
+            elem,
         }
     }
 
@@ -1750,7 +1750,7 @@ impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             Literal::Item { def_id, substs } => Literal::Item {
-                def_id: def_id,
+                def_id,
                 substs: substs.fold_with(folder)
             },
             _ => self.clone()
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 6078778a61d50..71acb36ecf75d 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
                              })
                              .ty;
                 LvalueTy::Ty {
-                    ty: ty,
+                    ty,
                 }
             }
             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
@@ -85,8 +85,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
                         assert!(adt_def.is_enum());
                         assert!(index < adt_def.variants.len());
                         assert_eq!(adt_def, adt_def1);
-                        LvalueTy::Downcast { adt_def: adt_def,
-                                             substs: substs,
+                        LvalueTy::Downcast { adt_def,
+                                             substs,
                                              variant_index: index }
                     }
                     _ => {
@@ -104,9 +104,9 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
             LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) },
             LvalueTy::Downcast { adt_def, substs, variant_index } => {
                 LvalueTy::Downcast {
-                    adt_def: adt_def,
+                    adt_def,
                     substs: substs.fold_with(folder),
-                    variant_index: variant_index
+                    variant_index,
                 }
             }
         }
diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs
index 6057e7ec7e0f5..5aab46b3cefb4 100644
--- a/src/librustc/mir/traversal.rs
+++ b/src/librustc/mir/traversal.rs
@@ -44,9 +44,9 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> {
         let worklist = vec![root];
 
         Preorder {
-            mir: mir,
+            mir,
             visited: BitVector::new(mir.basic_blocks().len()),
-            worklist: worklist
+            worklist,
         }
     }
 }
@@ -106,7 +106,7 @@ pub struct Postorder<'a, 'tcx: 'a> {
 impl<'a, 'tcx> Postorder<'a, 'tcx> {
     pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
         let mut po = Postorder {
-            mir: mir,
+            mir,
             visited: BitVector::new(mir.basic_blocks().len()),
             visit_stack: Vec::new()
         };
@@ -251,8 +251,8 @@ impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
         let len = blocks.len();
 
         ReversePostorder {
-            mir: mir,
-            blocks: blocks,
+            mir,
+            blocks,
             idx: len
         }
     }
diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs
index 215539de6766e..118b84113a0ff 100644
--- a/src/librustc/session/code_stats.rs
+++ b/src/librustc/session/code_stats.rs
@@ -82,12 +82,12 @@ impl CodeStats {
                                          opt_discr_size: Option<Size>,
                                          variants: Vec<VariantInfo>) {
         let info = TypeSizeInfo {
-            kind: kind,
+            kind,
             type_description: type_desc.to_string(),
             align: align.abi(),
             overall_size: overall_size.bytes(),
             opt_discr_size: opt_discr_size.map(|s| s.bytes()),
-            variants: variants,
+            variants,
         };
         self.type_sizes.insert(info);
     }
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 4f7ad5ea939f1..240f000a424c0 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1122,9 +1122,9 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
     };
 
     Config {
-        target: target,
-        int_type: int_type,
-        uint_type: uint_type,
+        target,
+        int_type,
+        uint_type,
     }
 }
 
@@ -1150,7 +1150,7 @@ impl RustcOptGroup {
         where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
     {
         RustcOptGroup {
-            name: name,
+            name,
             apply: Box::new(f),
             stability: OptionStability::Stable,
         }
@@ -1160,7 +1160,7 @@ impl RustcOptGroup {
         where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
     {
         RustcOptGroup {
-            name: name,
+            name,
             apply: Box::new(f),
             stability: OptionStability::Unstable,
         }
@@ -1627,28 +1627,28 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
     let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
 
     (Options {
-        crate_types: crate_types,
+        crate_types,
         optimize: opt_level,
-        debuginfo: debuginfo,
-        lint_opts: lint_opts,
-        lint_cap: lint_cap,
-        describe_lints: describe_lints,
+        debuginfo,
+        lint_opts,
+        lint_cap,
+        describe_lints,
         output_types: OutputTypes(output_types),
-        search_paths: search_paths,
+        search_paths,
         maybe_sysroot: sysroot_opt,
         target_triple: target,
-        test: test,
-        incremental: incremental,
-        debugging_opts: debugging_opts,
-        prints: prints,
-        cg: cg,
-        error_format: error_format,
+        test,
+        incremental,
+        debugging_opts,
+        prints,
+        cg,
+        error_format,
         externs: Externs(externs),
-        crate_name: crate_name,
+        crate_name,
         alt_std_name: None,
-        libs: libs,
+        libs,
         unstable_features: UnstableFeatures::from_environment(),
-        debug_assertions: debug_assertions,
+        debug_assertions,
         actually_rustdoc: false,
     },
     cfg)
diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs
index 47b988a21b4c1..1004b2826022a 100644
--- a/src/librustc/session/filesearch.rs
+++ b/src/librustc/session/filesearch.rs
@@ -104,10 +104,10 @@ impl<'a> FileSearch<'a> {
                kind: PathKind) -> FileSearch<'a> {
         debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
         FileSearch {
-            sysroot: sysroot,
-            search_paths: search_paths,
-            triple: triple,
-            kind: kind,
+            sysroot,
+            search_paths,
+            triple,
+            kind,
         }
     }
 
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 8bafdda234a09..fe6b24f3e1f2a 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -16,6 +16,7 @@ use hir::def_id::{CrateNum, DefIndex};
 
 use lint;
 use middle::cstore::CrateStore;
+use middle::allocator::AllocatorKind;
 use middle::dependency_format;
 use session::search_paths::PathKind;
 use session::config::DebugInfoLevel;
@@ -106,6 +107,7 @@ pub struct Session {
     /// dependency if it didn't already find one, and this tracks what was
     /// injected.
     pub injected_allocator: Cell<Option<CrateNum>>,
+    pub allocator_kind: Cell<Option<AllocatorKind>>,
     pub injected_panic_runtime: Cell<Option<CrateNum>>,
 
     /// Map from imported macro spans (which consist of
@@ -140,6 +142,9 @@ pub struct Session {
     /// Loaded up early on in the initialization of this `Session` to avoid
     /// false positives about a job server in our environment.
     pub jobserver_from_env: Option<Client>,
+
+    /// Metadata about the allocators for the current crate being compiled
+    pub has_global_allocator: Cell<bool>,
 }
 
 pub struct PerfStats {
@@ -480,7 +485,7 @@ impl Session {
 
         *incr_comp_session = IncrCompSession::Active {
             session_directory: session_dir,
-            lock_file: lock_file,
+            lock_file,
         };
     }
 
@@ -510,7 +515,7 @@ impl Session {
 
         // Note: This will also drop the lock file, thus unlocking the directory
         *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors {
-            session_directory: session_directory
+            session_directory,
         };
     }
 
@@ -690,18 +695,18 @@ pub fn build_session_(sopts: config::Options,
     let sess = Session {
         dep_graph: dep_graph.clone(),
         target: target_cfg,
-        host: host,
+        host,
         opts: sopts,
-        cstore: cstore,
+        cstore,
         parse_sess: p_s,
         // For a library crate, this is always none
         entry_fn: RefCell::new(None),
         entry_type: Cell::new(None),
         plugin_registrar_fn: Cell::new(None),
         derive_registrar_fn: Cell::new(None),
-        default_sysroot: default_sysroot,
-        local_crate_source_file: local_crate_source_file,
-        working_dir: working_dir,
+        default_sysroot,
+        local_crate_source_file,
+        working_dir,
         lint_store: RefCell::new(lint::LintStore::new()),
         lints: RefCell::new(lint::LintTable::new()),
         one_time_diagnostics: RefCell::new(FxHashSet()),
@@ -715,6 +720,7 @@ pub fn build_session_(sopts: config::Options,
         type_length_limit: Cell::new(1048576),
         next_node_id: Cell::new(NodeId::new(1)),
         injected_allocator: Cell::new(None),
+        allocator_kind: Cell::new(None),
         injected_panic_runtime: Cell::new(None),
         imported_macro_spans: RefCell::new(HashMap::new()),
         incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
@@ -727,12 +733,11 @@ pub fn build_session_(sopts: config::Options,
             decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
         },
         code_stats: RefCell::new(CodeStats::new()),
-        optimization_fuel_crate: optimization_fuel_crate,
-        optimization_fuel_limit: optimization_fuel_limit,
-        print_fuel_crate: print_fuel_crate,
-        print_fuel: print_fuel,
+        optimization_fuel_crate,
+        optimization_fuel_limit,
+        print_fuel_crate,
+        print_fuel,
         out_of_fuel: Cell::new(false),
-
         // Note that this is unsafe because it may misinterpret file descriptors
         // on Unix as jobserver file descriptors. We hopefully execute this near
         // the beginning of the process though to ensure we don't get false
@@ -750,6 +755,7 @@ pub fn build_session_(sopts: config::Options,
             });
             (*GLOBAL_JOBSERVER).clone()
         },
+        has_global_allocator: Cell::new(false),
     };
 
     sess
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 54fe3a42b6179..34df447a11e15 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -47,7 +47,7 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, '
     let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
 
     let header = ty::ImplHeader {
-        impl_def_id: impl_def_id,
+        impl_def_id,
         self_ty: tcx.type_of(impl_def_id),
         trait_ref: tcx.impl_trait_ref(impl_def_id),
         predicates: tcx.predicates_of(impl_def_id).predicates
@@ -102,7 +102,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
                      .chain(&b_impl_header.predicates)
                      .map(|p| infcx.resolve_type_vars_if_possible(p))
                      .map(|p| Obligation { cause: ObligationCause::dummy(),
-                                           param_env: param_env,
+                                           param_env,
                                            recursion_depth: 0,
                                            predicate: p })
                      .chain(obligations)
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 16ecc94b9476a..d0bb1adbabb2d 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -152,11 +152,11 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
                           cause: ObligationCause<'tcx>)
     {
         let trait_ref = ty::TraitRef {
-            def_id: def_id,
+            def_id,
             substs: infcx.tcx.mk_substs_trait(ty, &[]),
         };
         self.register_predicate_obligation(infcx, Obligation {
-            cause: cause,
+            cause,
             recursion_depth: 0,
             param_env,
             predicate: trait_ref.to_predicate()
@@ -191,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
         }
 
         self.predicates.register_obligation(PendingPredicateObligation {
-            obligation: obligation,
+            obligation,
             stalled_on: vec![]
         });
     }
@@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
 
             // Process pending obligations.
             let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
-                selcx: selcx,
+                selcx,
                 region_obligations: &mut self.region_obligations,
             });
             debug!("select: outcome={:?}", outcome);
@@ -606,7 +606,7 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
     pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'gcx> {
         GlobalFulfilledPredicates {
             set: FxHashSet(),
-            dep_graph: dep_graph,
+            dep_graph,
         }
     }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 16c41c816b4eb..6b243ffa5feb5 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -396,7 +396,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
            infcx.tcx.item_path_str(def_id));
 
     let trait_ref = ty::TraitRef {
-        def_id: def_id,
+        def_id,
         substs: infcx.tcx.mk_substs_trait(ty, &[]),
     };
     let obligation = Obligation {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index c356e53234d9c..14b6d4605e89f 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -245,11 +245,11 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
            -> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx>
     {
         AssociatedTypeNormalizer {
-            selcx: selcx,
-            param_env: param_env,
-            cause: cause,
+            selcx,
+            param_env,
+            cause,
             obligations: vec![],
-            depth: depth,
+            depth,
         }
     }
 
@@ -371,7 +371,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             let ty_var = selcx.infcx().next_ty_var(
                 TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
             let projection = ty::Binder(ty::ProjectionPredicate {
-                projection_ty: projection_ty,
+                projection_ty,
                 ty: ty_var
             });
             let obligation = Obligation::with_depth(
@@ -514,12 +514,12 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                 obligations.extend(normalizer.obligations);
                 Normalized {
                     value: normalized_ty,
-                    obligations: obligations,
+                    obligations,
                 }
             } else {
                 Normalized {
                     value: projected_ty,
-                    obligations: obligations,
+                    obligations,
                 }
             };
             infcx.projection_cache.borrow_mut()
@@ -586,7 +586,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
                                       -> NormalizedTy<'tcx>
 {
     let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
-    let trait_obligation = Obligation { cause: cause,
+    let trait_obligation = Obligation { cause,
                                         recursion_depth: depth,
                                         param_env,
                                         predicate: trait_ref.to_predicate() };
@@ -1232,7 +1232,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
         Ok(InferOk { value: ty_match, obligations }) => {
             Progress {
                 ty: ty_match.value,
-                obligations: obligations,
+                obligations,
                 cacheable: ty_match.unconstrained_regions.is_empty(),
             }
         }
@@ -1306,7 +1306,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
         if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
             return specialization_graph::NodeItem {
                 node: specialization_graph::Node::Impl(impl_def_id),
-                item: item,
+                item,
             };
         }
     }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 856fea7c2c437..4d4693f1c6468 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -212,7 +212,7 @@ impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> {
         Some(match *self {
             BuiltinCandidate { has_nested } => {
                 BuiltinCandidate {
-                    has_nested: has_nested
+                    has_nested,
                 }
             }
             ImplCandidate(def_id) => ImplCandidate(def_id),
@@ -290,7 +290,7 @@ pub struct EvaluationCache<'tcx> {
 impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx, 'tcx> {
         SelectionContext {
-            infcx: infcx,
+            infcx,
             freshener: infcx.freshener(),
             intercrate: false,
             inferred_obligations: SnapshotVec::new(),
@@ -299,7 +299,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
     pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx, 'tcx> {
         SelectionContext {
-            infcx: infcx,
+            infcx,
             freshener: infcx.freshener(),
             intercrate: true,
             inferred_obligations: SnapshotVec::new(),
@@ -2205,7 +2205,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         debug!("vtable_default_impl: obligations={:?}", obligations);
 
         VtableDefaultImplData {
-            trait_def_id: trait_def_id,
+            trait_def_id,
             nested: obligations
         }
     }
@@ -2273,7 +2273,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // e.g. `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
         impl_obligations.append(&mut substs.obligations);
 
-        VtableImplData { impl_def_id: impl_def_id,
+        VtableImplData { impl_def_id,
                          substs: substs.value,
                          nested: impl_obligations }
     }
@@ -2336,7 +2336,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         VtableObjectData {
             upcast_trait_ref: upcast_trait_ref.unwrap(),
-            vtable_base: vtable_base,
+            vtable_base,
             nested: vec![]
         }
     }
@@ -2405,7 +2405,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             ty::Predicate::ClosureKind(closure_def_id, kind)));
 
         Ok(VtableClosureData {
-            closure_def_id: closure_def_id,
+            closure_def_id,
             substs: substs.clone(),
             nested: obligations
         })
@@ -2826,8 +2826,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
 
         TraitObligationStack {
-            obligation: obligation,
-            fresh_trait_ref: fresh_trait_ref,
+            obligation,
+            fresh_trait_ref,
             previous: previous_stack,
         }
     }
@@ -2911,7 +2911,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             predicate.obligations.into_iter().chain(
                 Some(Obligation {
                     cause: cause.clone(),
-                    recursion_depth: recursion_depth,
+                    recursion_depth,
                     param_env,
                     predicate: predicate.value
                 }))
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index c4479e6903267..f1c176561ea48 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -209,15 +209,15 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
                                                  trait_item_def_id,
                                                  lint_id } => {
                 Some(super::CompareImplMethodObligation {
-                    item_name: item_name,
-                    impl_item_def_id: impl_item_def_id,
-                    trait_item_def_id: trait_item_def_id,
-                    lint_id: lint_id,
+                    item_name,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                    lint_id,
                 })
             }
             super::ExprAssignable => Some(super::ExprAssignable),
             super::MatchExpressionArm { arm_span, source } => {
-                Some(super::MatchExpressionArm { arm_span: arm_span,
+                Some(super::MatchExpressionArm { arm_span,
                                                  source: source })
             }
             super::IfExpression => Some(super::IfExpression),
@@ -253,7 +253,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
             traits::ObligationCause {
                 span: self.span,
                 body_id: self.body_id,
-                code: code,
+                code,
             }
         })
     }
@@ -271,9 +271,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
             }) => {
                 tcx.lift(&substs).map(|substs| {
                     traits::VtableImpl(traits::VtableImplData {
-                        impl_def_id: impl_def_id,
-                        substs: substs,
-                        nested: nested
+                        impl_def_id,
+                        substs,
+                        nested,
                     })
                 })
             }
@@ -285,17 +285,17 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
             }) => {
                 tcx.lift(&substs).map(|substs| {
                     traits::VtableClosure(traits::VtableClosureData {
-                        closure_def_id: closure_def_id,
-                        substs: substs,
-                        nested: nested
+                        closure_def_id,
+                        substs,
+                        nested,
                     })
                 })
             }
             traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => {
                 tcx.lift(&fn_ty).map(|fn_ty| {
                     traits::VtableFnPointer(traits::VtableFnPointerData {
-                        fn_ty: fn_ty,
-                        nested: nested,
+                        fn_ty,
+                        nested,
                     })
                 })
             }
@@ -309,8 +309,8 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
                 tcx.lift(&upcast_trait_ref).map(|trait_ref| {
                     traits::VtableObject(traits::VtableObjectData {
                         upcast_trait_ref: trait_ref,
-                        vtable_base: vtable_base,
-                        nested: nested
+                        vtable_base,
+                        nested,
                     })
                 })
             }
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index c385927811cf7..dae0c896909c8 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -288,7 +288,7 @@ pub fn supertrait_def_ids<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
                                            -> SupertraitDefIds<'cx, 'gcx, 'tcx>
 {
     SupertraitDefIds {
-        tcx: tcx,
+        tcx,
         stack: vec![trait_def_id],
         visited: Some(trait_def_id).into_iter().collect(),
     }
@@ -399,8 +399,8 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
 
     generic_bounds.predicates.iter().map(|predicate| {
         Obligation { cause: cause.clone(),
-                     recursion_depth: recursion_depth,
-                     param_env: param_env,
+                     recursion_depth,
+                     param_env,
                      predicate: predicate.clone() }
     }).collect()
 }
@@ -413,9 +413,9 @@ pub fn predicate_for_trait_ref<'tcx>(
     -> PredicateObligation<'tcx>
 {
     Obligation {
-        cause: cause,
-        param_env: param_env,
-        recursion_depth: recursion_depth,
+        cause,
+        param_env,
+        recursion_depth,
         predicate: trait_ref.to_predicate(),
     }
 }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 5f869fc5567ee..316f871a7a46c 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -107,7 +107,7 @@ pub struct CtxtInterners<'tcx> {
 impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
     fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> {
         CtxtInterners {
-            arena: arena,
+            arena,
             type_: RefCell::new(FxHashSet()),
             type_list: RefCell::new(FxHashSet()),
             substs: RefCell::new(FxHashSet()),
@@ -732,12 +732,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             global_interners: interners,
             dep_graph: dep_graph.clone(),
             types: common_types,
-            named_region_map: named_region_map,
+            named_region_map,
             trait_map: resolutions.trait_map,
             export_map: resolutions.export_map,
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
-            hir: hir,
-            def_path_hash_to_def_id: def_path_hash_to_def_id,
+            hir,
+            def_path_hash_to_def_id,
             maps: maps::Maps::new(providers),
             mir_passes,
             freevars: RefCell::new(resolutions.freevars),
@@ -745,7 +745,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             rcache: RefCell::new(FxHashMap()),
             normalized_cache: RefCell::new(FxHashMap()),
             inhabitedness_cache: RefCell::new(FxHashMap()),
-            lang_items: lang_items,
+            lang_items,
             used_unsafe: RefCell::new(NodeSet()),
             used_mut_nodes: RefCell::new(NodeSet()),
             stability: RefCell::new(stability),
@@ -753,7 +753,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             evaluation_cache: traits::EvaluationCache::new(),
             rvalue_promotable_to_static: RefCell::new(NodeMap()),
             crate_name: Symbol::intern(crate_name),
-            data_layout: data_layout,
+            data_layout,
             layout_interner: RefCell::new(FxHashSet()),
             layout_depth: Cell::new(0),
             derive_macros: RefCell::new(NodeMap()),
@@ -964,8 +964,8 @@ pub mod tls {
             let prev = tls.get();
             tls.set(Some((gcx_ptr, interners_ptr)));
             let ret = f(TyCtxt {
-                gcx: gcx,
-                interners: interners
+                gcx,
+                interners,
             });
             tls.set(prev);
             ret
@@ -980,8 +980,8 @@ pub mod tls {
             let gcx = unsafe { &*(gcx as *const GlobalCtxt) };
             let interners = unsafe { &*(interners as *const CtxtInterners) };
             f(TyCtxt {
-                gcx: gcx,
-                interners: interners
+                gcx,
+                interners,
             })
         })
     }
@@ -1408,7 +1408,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                       substs: &'tcx Substs<'tcx>)
         -> Ty<'tcx> {
         self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
-            substs: substs
+            substs,
         })
     }
 
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index bb13031a2b7c4..66868040925e1 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -238,10 +238,10 @@ impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> {
         where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx>
     {
         RegionFolder {
-            tcx: tcx,
-            skipped_regions: skipped_regions,
+            tcx,
+            skipped_regions,
             current_depth: 1,
-            fld_r: fld_r,
+            fld_r,
         }
     }
 }
@@ -393,9 +393,9 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
         where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>
     {
         RegionReplacer {
-            tcx: tcx,
+            tcx,
             current_depth: 1,
-            fld_r: fld_r,
+            fld_r,
             map: FxHashMap()
         }
     }
@@ -621,7 +621,7 @@ impl LateBoundRegionsCollector {
         LateBoundRegionsCollector {
             current_depth: 1,
             regions: FxHashSet(),
-            just_constrained: just_constrained,
+            just_constrained,
         }
     }
 }
diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs
index 6801e82fe7476..231600f95ac60 100644
--- a/src/librustc/ty/inhabitedness/def_id_forest.rs
+++ b/src/librustc/ty/inhabitedness/def_id_forest.rs
@@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> DefIdForest {
         let mut root_ids = SmallVec::new();
         root_ids.push(id);
         DefIdForest {
-            root_ids: root_ids,
+            root_ids,
         }
     }
 
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index b9896e0cecf5d..73b577e2e876b 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -397,7 +397,7 @@ struct LocalPathBuffer {
 impl LocalPathBuffer {
     fn new(root_mode: RootMode) -> LocalPathBuffer {
         LocalPathBuffer {
-            root_mode: root_mode,
+            root_mode,
             str: String::new(),
         }
     }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index e1aa89078a33b..3212c6f07d1d6 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -609,7 +609,7 @@ impl<'a, 'tcx> Struct {
         };
 
         let mut ret = Struct {
-            align: align,
+            align,
             primitive_align: align,
             packed: repr.packed(),
             sized: true,
@@ -910,10 +910,10 @@ impl<'a, 'tcx> Union {
     fn new(dl: &TargetDataLayout, packed: bool) -> Union {
         let align = if packed { dl.i8_align } else { dl.aggregate_align };
         Union {
-            align: align,
+            align,
             primitive_align: align,
             min_size: Size::from_bytes(0),
-            packed: packed,
+            packed,
         }
     }
 
@@ -1169,8 +1169,8 @@ impl<'a, 'tcx> Layout {
                     sized: true,
                     align: element.align(dl),
                     primitive_align: element.primitive_align(dl),
-                    element_size: element_size,
-                    count: count
+                    element_size,
+                    count,
                 }
             }
             ty::TySlice(element) => {
@@ -1280,9 +1280,9 @@ impl<'a, 'tcx> Layout {
                     // grok.
                     let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
                     return success(CEnum {
-                        discr: discr,
-                        signed: signed,
-                        non_zero: non_zero,
+                        discr,
+                        signed,
+                        non_zero,
                         // FIXME: should be u128?
                         min: min as u64,
                         max: max as u64
@@ -1364,7 +1364,7 @@ impl<'a, 'tcx> Layout {
                             };
                             return success(RawNullablePointer {
                                 nndiscr: discr as u64,
-                                value: value,
+                                value,
                             });
                         }
 
@@ -1491,10 +1491,10 @@ impl<'a, 'tcx> Layout {
 
                 General {
                     discr: ity,
-                    variants: variants,
-                    size: size,
-                    align: align,
-                    primitive_align: primitive_align
+                    variants,
+                    size,
+                    align,
+                    primitive_align,
                 }
             }
 
@@ -1957,7 +1957,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
                 ty::TyParam(_) | ty::TyProjection(_) => {
                     assert!(tail.has_param_types() || tail.has_self_ty());
                     Ok(SizeSkeleton::Pointer {
-                        non_zero: non_zero,
+                        non_zero,
                         tail: tcx.erase_regions(&tail)
                     })
                 }
@@ -2016,7 +2016,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
                         return Ok(SizeSkeleton::Pointer {
                             non_zero: non_zero ||
                                 Some(def.did) == tcx.lang_items.non_zero(),
-                            tail: tail
+                            tail,
                         });
                     } else {
                         return Err(err);
@@ -2030,7 +2030,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
                     (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
                         Ok(SizeSkeleton::Pointer {
                             non_zero: false,
-                            tail: tail
+                            tail,
                         })
                     }
                     _ => Err(err)
@@ -2115,7 +2115,7 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> {
         let ty = self.normalize_projections(ty);
 
         Ok(TyLayout {
-            ty: ty,
+            ty,
             layout: ty.layout(self.tcx, self.param_env)?,
             variant_index: None
         })
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index a6c59d4c22354..f4e333228c94d 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             if let Some((i, _)) = stack.iter().enumerate().rev()
                                        .find(|&(_, &(_, ref q))| *q == query) {
                 return Err(CycleError {
-                    span: span,
+                    span,
                     cycle: RefMut::map(stack, |stack| &mut stack[i..])
                 });
             }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 548ee7bcbe503..88aef53ec9de5 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -964,8 +964,8 @@ impl<'tcx> TraitPredicate<'tcx> {
                 .next()
                 .unwrap_or(trait_def_id);
         DepNode::new(tcx, DepConstructor::TraitSelect {
-            trait_def_id: trait_def_id,
-            input_def_id: input_def_id
+            trait_def_id,
+            input_def_id,
         })
     }
 
@@ -1244,12 +1244,12 @@ impl<'tcx> ParamEnv<'tcx> {
         if value.has_param_types() || value.has_self_ty() {
             ParamEnvAnd {
                 param_env: self,
-                value: value,
+                value,
             }
         } else {
             ParamEnvAnd {
                 param_env: ParamEnv::empty(self.reveal),
-                value: value,
+                value,
             }
         }
     }
@@ -1487,10 +1487,10 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             AdtKind::Struct => {}
         }
         AdtDef {
-            did: did,
-            variants: variants,
-            flags: flags,
-            repr: repr,
+            did,
+            variants,
+            flags,
+            repr,
         }
     }
 
@@ -2113,11 +2113,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         AssociatedItem {
             name: trait_item_ref.name,
-            kind: kind,
+            kind,
             // Visibility of trait items is inherited from their traits.
             vis: Visibility::from_hir(parent_vis, trait_item_ref.id.node_id, self),
             defaultness: trait_item_ref.defaultness,
-            def_id: def_id,
+            def_id,
             container: TraitContainer(parent_def_id),
             method_has_self_argument: has_self
         }
@@ -2138,11 +2138,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         ty::AssociatedItem {
             name: impl_item_ref.name,
-            kind: kind,
+            kind,
             // Visibility of trait impl items doesn't matter.
             vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.node_id, self),
             defaultness: impl_item_ref.defaultness,
-            def_id: def_id,
+            def_id,
             container: ImplContainer(parent_def_id),
             method_has_self_argument: has_self
         }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 2e9780572c9b4..7710cc965c8f0 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -182,8 +182,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
         Ok(ty::FnSig {
             inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output),
             variadic: a.variadic,
-            unsafety: unsafety,
-            abi: abi
+            unsafety,
+            abi,
         })
     }
 }
@@ -250,9 +250,9 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
             let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?;
             let ty = relation.relate(&a.ty, &b.ty)?;
             Ok(ty::ExistentialProjection {
-                trait_ref: trait_ref,
+                trait_ref,
                 item_name: a.item_name,
-                ty: ty
+                ty,
             })
         }
     }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index d05262965d7fd..478717eaca097 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -78,7 +78,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> {
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         tcx.lift(&self.substs).map(|substs| ty::TraitRef {
             def_id: self.def_id,
-            substs: substs
+            substs,
         })
     }
 }
@@ -88,7 +88,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> {
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         tcx.lift(&self.substs).map(|substs| ty::ExistentialTraitRef {
             def_id: self.def_id,
-            substs: substs
+            substs,
         })
     }
 }
@@ -98,7 +98,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
                              -> Option<ty::TraitPredicate<'tcx>> {
         tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate {
-            trait_ref: trait_ref
+            trait_ref,
         })
     }
 }
@@ -117,8 +117,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
                              -> Option<ty::SubtypePredicate<'tcx>> {
         tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate {
             a_is_expected: self.a_is_expected,
-            a: a,
-            b: b,
+            a,
+            b,
         })
     }
 }
@@ -146,8 +146,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
                              -> Option<ty::ProjectionPredicate<'tcx>> {
         tcx.lift(&(self.projection_ty, self.ty)).map(|(projection_ty, ty)| {
             ty::ProjectionPredicate {
-                projection_ty: projection_ty,
-                ty: ty
+                projection_ty,
+                ty,
             }
         })
     }
@@ -158,9 +158,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         tcx.lift(&(self.trait_ref, self.ty)).map(|(trait_ref, ty)| {
             ty::ExistentialProjection {
-                trait_ref: trait_ref,
+                trait_ref,
                 item_name: self.item_name,
-                ty: ty
+                ty,
             }
         })
     }
@@ -300,8 +300,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> {
         tcx.lift(&self.expected).and_then(|expected| {
             tcx.lift(&self.found).map(|found| {
                 ty::error::ExpectedFound {
-                    expected: expected,
-                    found: found
+                    expected,
+                    found,
                 }
             })
         })
@@ -313,7 +313,7 @@ impl<'a, 'tcx> Lift<'tcx> for type_variable::Default<'a> {
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         tcx.lift(&self.ty).map(|ty| {
             type_variable::Default {
-                ty: ty,
+                ty,
                 origin_span: self.origin_span,
                 def_id: self.def_id
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 452775e9e1337..737e69b658348 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -571,8 +571,8 @@ impl<'a, 'tcx> ProjectionTy<'tcx> {
             |item| item.name == item_name).unwrap().def_id;
 
         ProjectionTy {
-            trait_ref: trait_ref,
-            item_def_id: item_def_id,
+            trait_ref,
+            item_def_id,
         }
     }
 
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index d0d61323392c7..f6112d4887d7d 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -352,9 +352,9 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
                                span: Option<Span>)
                                -> T
     {
-        let mut folder = SubstFolder { tcx: tcx,
-                                       substs: substs,
-                                       span: span,
+        let mut folder = SubstFolder { tcx,
+                                       substs,
+                                       span,
                                        root_ty: None,
                                        ty_stack_depth: 0,
                                        region_binders_passed: 0 };
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 2eb0acac4f7ec..91bc56155969a 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -31,10 +31,10 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                    span: Span)
                                    -> Option<Vec<traits::PredicateObligation<'tcx>>>
 {
-    let mut wf = WfPredicates { infcx: infcx,
-                                param_env: param_env,
-                                body_id: body_id,
-                                span: span,
+    let mut wf = WfPredicates { infcx,
+                                param_env,
+                                body_id,
+                                span,
                                 out: vec![] };
     if wf.compute(ty) {
         debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
diff --git a/src/libproc_macro_plugin/Cargo.toml b/src/librustc_allocator/Cargo.toml
similarity index 64%
rename from src/libproc_macro_plugin/Cargo.toml
rename to src/librustc_allocator/Cargo.toml
index 146a66cdf01cb..e3d1d8e32c4b7 100644
--- a/src/libproc_macro_plugin/Cargo.toml
+++ b/src/librustc_allocator/Cargo.toml
@@ -1,13 +1,15 @@
 [package]
 authors = ["The Rust Project Developers"]
-name = "proc_macro_plugin"
+name = "rustc_allocator"
 version = "0.0.0"
 
 [lib]
 path = "lib.rs"
 crate-type = ["dylib"]
+test = false
 
 [dependencies]
-rustc_plugin = { path = "../librustc_plugin" }
+rustc = { path = "../librustc" }
+rustc_errors = { path = "../librustc_errors" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
new file mode 100644
index 0000000000000..e942b7264c589
--- /dev/null
+++ b/src/librustc_allocator/expand.rs
@@ -0,0 +1,498 @@
+// 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.
+
+use rustc::middle::allocator::AllocatorKind;
+use rustc_errors;
+use syntax::abi::Abi;
+use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind};
+use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg};
+use syntax::ast::{self, Ident, Item, ItemKind, TyKind, Visibility, Expr};
+use syntax::attr;
+use syntax::codemap::dummy_spanned;
+use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
+use syntax::ext::base::ExtCtxt;
+use syntax::ext::base::Resolver;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::expand::ExpansionConfig;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::fold::{self, Folder};
+use syntax::parse::ParseSess;
+use syntax::ptr::P;
+use syntax::symbol::Symbol;
+use syntax::util::small_vector::SmallVector;
+use syntax_pos::{Span, DUMMY_SP};
+
+use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
+
+pub fn modify(sess: &ParseSess,
+              resolver: &mut Resolver,
+              krate: Crate,
+              handler: &rustc_errors::Handler) -> ast::Crate {
+    ExpandAllocatorDirectives {
+        handler: handler,
+        sess: sess,
+        resolver: resolver,
+        found: false,
+    }.fold_crate(krate)
+}
+
+struct ExpandAllocatorDirectives<'a> {
+    found: bool,
+    handler: &'a rustc_errors::Handler,
+    sess: &'a ParseSess,
+    resolver: &'a mut Resolver,
+}
+
+impl<'a> Folder for ExpandAllocatorDirectives<'a> {
+    fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
+        let name = if attr::contains_name(&item.attrs, "global_allocator") {
+            "global_allocator"
+        } else {
+            return fold::noop_fold_item(item, self)
+        };
+        match item.node {
+            ItemKind::Static(..) => {}
+            _ => {
+                self.handler.span_err(item.span, "allocators must be statics");
+                return SmallVector::one(item)
+            }
+        }
+
+        if self.found {
+            self.handler.span_err(item.span, "cannot define more than one \
+                                              #[global_allocator]");
+            return SmallVector::one(item)
+        }
+        self.found = true;
+
+        let mark = Mark::fresh(Mark::root());
+        mark.set_expn_info(ExpnInfo {
+            call_site: DUMMY_SP,
+            callee: NameAndSpan {
+                format: MacroAttribute(Symbol::intern(name)),
+                span: None,
+                allow_internal_unstable: true,
+            }
+        });
+        let span = Span {
+            ctxt: SyntaxContext::empty().apply_mark(mark),
+            ..item.span
+        };
+        let ecfg = ExpansionConfig::default(name.to_string());
+        let mut f = AllocFnFactory {
+            span: span,
+            kind: AllocatorKind::Global,
+            global: item.ident,
+            alloc: Ident::from_str("alloc"),
+            cx: ExtCtxt::new(self.sess, ecfg, self.resolver),
+        };
+        let super_path = f.cx.path(f.span, vec![
+            Ident::from_str("super"),
+            f.global,
+        ]);
+        let mut items = vec![
+            f.cx.item_extern_crate(f.span, f.alloc),
+            f.cx.item_use_simple(f.span, Visibility::Inherited, super_path),
+        ];
+        for method in ALLOCATOR_METHODS {
+            items.push(f.allocator_fn(method));
+        }
+        let name = f.kind.fn_name("allocator_abi");
+        let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name));
+        let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items);
+        let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap();
+
+        let mut ret = SmallVector::new();
+        ret.push(item);
+        ret.push(module);
+        return ret
+    }
+
+    fn fold_mac(&mut self, mac: Mac) -> Mac {
+        fold::noop_fold_mac(mac, self)
+    }
+}
+
+struct AllocFnFactory<'a> {
+    span: Span,
+    kind: AllocatorKind,
+    global: Ident,
+    alloc: Ident,
+    cx: ExtCtxt<'a>,
+}
+
+impl<'a> AllocFnFactory<'a> {
+    fn allocator_fn(&self, method: &AllocatorMethod) -> P<Item> {
+        let mut abi_args = Vec::new();
+        let mut i = 0;
+        let ref mut mk = || {
+            let name = Ident::from_str(&format!("arg{}", i));
+            i += 1;
+            name
+        };
+        let args = method.inputs.iter().map(|ty| {
+            self.arg_ty(ty, &mut abi_args, mk)
+        }).collect();
+        let result = self.call_allocator(method.name, args);
+        let (output_ty, output_expr) =
+            self.ret_ty(&method.output, &mut abi_args, mk, result);
+        let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, output_ty),
+                                Unsafety::Unsafe,
+                                dummy_spanned(Constness::NotConst),
+                                Abi::Rust,
+                                Generics::default(),
+                                self.cx.block_expr(output_expr));
+        self.cx.item(self.span,
+                     Ident::from_str(&self.kind.fn_name(method.name)),
+                     self.attrs(),
+                     kind)
+    }
+
+    fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> {
+        let method = self.cx.path(self.span, vec![
+            self.alloc,
+            Ident::from_str("heap"),
+            Ident::from_str("Alloc"),
+            Ident::from_str(method),
+        ]);
+        let method = self.cx.expr_path(method);
+        let allocator = self.cx.path_ident(self.span, self.global);
+        let allocator = self.cx.expr_path(allocator);
+        let allocator = self.cx.expr_addr_of(self.span, allocator);
+        let allocator = self.cx.expr_mut_addr_of(self.span, allocator);
+        args.insert(0, allocator);
+
+        self.cx.expr_call(self.span, method, args)
+    }
+
+    fn attrs(&self) -> Vec<Attribute> {
+        let key = Symbol::intern("linkage");
+        let value = LitKind::Str(Symbol::intern("external"), StrStyle::Cooked);
+        let linkage = self.cx.meta_name_value(self.span, key, value);
+
+        let no_mangle = Symbol::intern("no_mangle");
+        let no_mangle = self.cx.meta_word(self.span, no_mangle);
+        vec![
+            self.cx.attribute(self.span, linkage),
+            self.cx.attribute(self.span, no_mangle),
+        ]
+    }
+
+    fn arg_ty(&self,
+              ty: &AllocatorTy,
+              args: &mut Vec<Arg>,
+              mut ident: &mut FnMut() -> Ident) -> P<Expr> {
+        match *ty {
+            AllocatorTy::Layout => {
+                let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
+                let ty_usize = self.cx.ty_path(usize);
+                let size = ident();
+                let align = ident();
+                args.push(self.cx.arg(self.span, size, ty_usize.clone()));
+                args.push(self.cx.arg(self.span, align, ty_usize));
+
+                let layout_new = self.cx.path(self.span, vec![
+                    self.alloc,
+                    Ident::from_str("heap"),
+                    Ident::from_str("Layout"),
+                    Ident::from_str("from_size_align_unchecked"),
+                ]);
+                let layout_new = self.cx.expr_path(layout_new);
+                let size = self.cx.expr_ident(self.span, size);
+                let align = self.cx.expr_ident(self.span, align);
+                let layout = self.cx.expr_call(self.span,
+                                               layout_new,
+                                               vec![size, align]);
+                layout
+            }
+
+            AllocatorTy::LayoutRef => {
+                let ident = ident();
+                args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
+
+                // Convert our `arg: *const u8` via:
+                //
+                //      &*(arg as *const Layout)
+                let expr = self.cx.expr_ident(self.span, ident);
+                let expr = self.cx.expr_cast(self.span, expr, self.layout_ptr());
+                let expr = self.cx.expr_deref(self.span, expr);
+                self.cx.expr_addr_of(self.span, expr)
+            }
+
+            AllocatorTy::AllocErr => {
+                // We're creating:
+                //
+                //      (*(arg as *const AllocErr)).clone()
+                let ident = ident();
+                args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
+                let expr = self.cx.expr_ident(self.span, ident);
+                let expr = self.cx.expr_cast(self.span, expr, self.alloc_err_ptr());
+                let expr = self.cx.expr_deref(self.span, expr);
+                self.cx.expr_method_call(
+                    self.span,
+                    expr,
+                    Ident::from_str("clone"),
+                    Vec::new()
+                )
+            }
+
+            AllocatorTy::Ptr => {
+                let ident = ident();
+                args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
+                self.cx.expr_ident(self.span, ident)
+            }
+
+            AllocatorTy::ResultPtr |
+            AllocatorTy::ResultExcess |
+            AllocatorTy::ResultUnit |
+            AllocatorTy::Bang |
+            AllocatorTy::UsizePair |
+            AllocatorTy::Unit => {
+                panic!("can't convert AllocatorTy to an argument")
+            }
+        }
+    }
+
+    fn ret_ty(&self,
+              ty: &AllocatorTy,
+              args: &mut Vec<Arg>,
+              mut ident: &mut FnMut() -> Ident,
+              expr: P<Expr>) -> (P<Ty>, P<Expr>)
+    {
+        match *ty {
+            AllocatorTy::UsizePair => {
+                // We're creating:
+                //
+                //      let arg = #expr;
+                //      *min = arg.0;
+                //      *max = arg.1;
+
+                let min = ident();
+                let max = ident();
+
+                args.push(self.cx.arg(self.span, min, self.ptr_usize()));
+                args.push(self.cx.arg(self.span, max, self.ptr_usize()));
+
+                let ident = ident();
+                let stmt = self.cx.stmt_let(self.span, false, ident, expr);
+                let min = self.cx.expr_ident(self.span, min);
+                let max = self.cx.expr_ident(self.span, max);
+                let layout = self.cx.expr_ident(self.span, ident);
+                let assign_min = self.cx.expr(self.span, ExprKind::Assign(
+                    self.cx.expr_deref(self.span, min),
+                    self.cx.expr_tup_field_access(self.span, layout.clone(), 0),
+                ));
+                let assign_min = self.cx.stmt_semi(assign_min);
+                let assign_max = self.cx.expr(self.span, ExprKind::Assign(
+                    self.cx.expr_deref(self.span, max),
+                    self.cx.expr_tup_field_access(self.span, layout.clone(), 1),
+                ));
+                let assign_max = self.cx.stmt_semi(assign_max);
+
+                let stmts = vec![stmt, assign_min, assign_max];
+                let block = self.cx.block(self.span, stmts);
+                let ty_unit = self.cx.ty(self.span, TyKind::Tup(Vec::new()));
+                (ty_unit, self.cx.expr_block(block))
+            }
+
+            AllocatorTy::ResultExcess => {
+                // We're creating:
+                //
+                //      match #expr {
+                //          Ok(ptr) => {
+                //              *excess = ptr.1;
+                //              ptr.0
+                //          }
+                //          Err(e) => {
+                //              ptr::write(err_ptr, e);
+                //              0 as *mut u8
+                //          }
+                //      }
+
+                let excess_ptr = ident();
+                args.push(self.cx.arg(self.span, excess_ptr, self.ptr_usize()));
+                let excess_ptr = self.cx.expr_ident(self.span, excess_ptr);
+
+                let err_ptr = ident();
+                args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8()));
+                let err_ptr = self.cx.expr_ident(self.span, err_ptr);
+                let err_ptr = self.cx.expr_cast(self.span,
+                                                err_ptr,
+                                                self.alloc_err_ptr());
+
+                let name = ident();
+                let ok_expr = {
+                    let ptr = self.cx.expr_ident(self.span, name);
+                    let write = self.cx.expr(self.span, ExprKind::Assign(
+                        self.cx.expr_deref(self.span, excess_ptr),
+                        self.cx.expr_tup_field_access(self.span, ptr.clone(), 1),
+                    ));
+                    let write = self.cx.stmt_semi(write);
+                    let ret = self.cx.expr_tup_field_access(self.span,
+                                                            ptr.clone(),
+                                                            0);
+                    let ret = self.cx.stmt_expr(ret);
+                    let block = self.cx.block(self.span, vec![write, ret]);
+                    self.cx.expr_block(block)
+                };
+                let pat = self.cx.pat_ident(self.span, name);
+                let ok = self.cx.path_ident(self.span, Ident::from_str("Ok"));
+                let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]);
+                let ok = self.cx.arm(self.span, vec![ok], ok_expr);
+
+                let name = ident();
+                let err_expr = {
+                    let err = self.cx.expr_ident(self.span, name);
+                    let write = self.cx.path(self.span, vec![
+                        self.alloc,
+                        Ident::from_str("heap"),
+                        Ident::from_str("__core"),
+                        Ident::from_str("ptr"),
+                        Ident::from_str("write"),
+                    ]);
+                    let write = self.cx.expr_path(write);
+                    let write = self.cx.expr_call(self.span, write,
+                                                  vec![err_ptr, err]);
+                    let write = self.cx.stmt_semi(write);
+                    let null = self.cx.expr_usize(self.span, 0);
+                    let null = self.cx.expr_cast(self.span, null, self.ptr_u8());
+                    let null = self.cx.stmt_expr(null);
+                    let block = self.cx.block(self.span, vec![write, null]);
+                    self.cx.expr_block(block)
+                };
+                let pat = self.cx.pat_ident(self.span, name);
+                let err = self.cx.path_ident(self.span, Ident::from_str("Err"));
+                let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]);
+                let err = self.cx.arm(self.span, vec![err], err_expr);
+
+                let expr = self.cx.expr_match(self.span, expr, vec![ok, err]);
+                (self.ptr_u8(), expr)
+            }
+
+            AllocatorTy::ResultPtr => {
+                // We're creating:
+                //
+                //      match #expr {
+                //          Ok(ptr) => ptr,
+                //          Err(e) => {
+                //              ptr::write(err_ptr, e);
+                //              0 as *mut u8
+                //          }
+                //      }
+
+                let err_ptr = ident();
+                args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8()));
+                let err_ptr = self.cx.expr_ident(self.span, err_ptr);
+                let err_ptr = self.cx.expr_cast(self.span,
+                                                err_ptr,
+                                                self.alloc_err_ptr());
+
+                let name = ident();
+                let ok_expr = self.cx.expr_ident(self.span, name);
+                let pat = self.cx.pat_ident(self.span, name);
+                let ok = self.cx.path_ident(self.span, Ident::from_str("Ok"));
+                let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]);
+                let ok = self.cx.arm(self.span, vec![ok], ok_expr);
+
+                let name = ident();
+                let err_expr = {
+                    let err = self.cx.expr_ident(self.span, name);
+                    let write = self.cx.path(self.span, vec![
+                        self.alloc,
+                        Ident::from_str("heap"),
+                        Ident::from_str("__core"),
+                        Ident::from_str("ptr"),
+                        Ident::from_str("write"),
+                    ]);
+                    let write = self.cx.expr_path(write);
+                    let write = self.cx.expr_call(self.span, write,
+                                                  vec![err_ptr, err]);
+                    let write = self.cx.stmt_semi(write);
+                    let null = self.cx.expr_usize(self.span, 0);
+                    let null = self.cx.expr_cast(self.span, null, self.ptr_u8());
+                    let null = self.cx.stmt_expr(null);
+                    let block = self.cx.block(self.span, vec![write, null]);
+                    self.cx.expr_block(block)
+                };
+                let pat = self.cx.pat_ident(self.span, name);
+                let err = self.cx.path_ident(self.span, Ident::from_str("Err"));
+                let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]);
+                let err = self.cx.arm(self.span, vec![err], err_expr);
+
+                let expr = self.cx.expr_match(self.span, expr, vec![ok, err]);
+                (self.ptr_u8(), expr)
+            }
+
+            AllocatorTy::ResultUnit => {
+                // We're creating:
+                //
+                //      #expr.is_ok() as u8
+
+                let cast = self.cx.expr_method_call(
+                    self.span,
+                    expr,
+                    Ident::from_str("is_ok"),
+                    Vec::new()
+                );
+                let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
+                let u8 = self.cx.ty_path(u8);
+                let cast = self.cx.expr_cast(self.span, cast, u8.clone());
+                (u8, cast)
+            }
+
+            AllocatorTy::Bang => {
+                (self.cx.ty(self.span, TyKind::Never), expr)
+            }
+
+            AllocatorTy::Unit => {
+                (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr)
+            }
+
+            AllocatorTy::AllocErr |
+            AllocatorTy::Layout |
+            AllocatorTy::LayoutRef |
+            AllocatorTy::Ptr => {
+                panic!("can't convert AllocatorTy to an output")
+            }
+        }
+    }
+
+    fn ptr_u8(&self) -> P<Ty> {
+        let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
+        let ty_u8 = self.cx.ty_path(u8);
+        self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
+    }
+
+    fn ptr_usize(&self) -> P<Ty> {
+        let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
+        let ty_usize = self.cx.ty_path(usize);
+        self.cx.ty_ptr(self.span, ty_usize, Mutability::Mutable)
+    }
+
+    fn layout_ptr(&self) -> P<Ty> {
+        let layout = self.cx.path(self.span, vec![
+            self.alloc,
+            Ident::from_str("heap"),
+            Ident::from_str("Layout"),
+        ]);
+        let layout = self.cx.ty_path(layout);
+        self.cx.ty_ptr(self.span, layout, Mutability::Mutable)
+    }
+
+    fn alloc_err_ptr(&self) -> P<Ty> {
+        let err = self.cx.path(self.span, vec![
+            self.alloc,
+            Ident::from_str("heap"),
+            Ident::from_str("AllocErr"),
+        ]);
+        let err = self.cx.ty_path(err);
+        self.cx.ty_ptr(self.span, err, Mutability::Mutable)
+    }
+}
diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs
new file mode 100644
index 0000000000000..d0ea40d1e361d
--- /dev/null
+++ b/src/librustc_allocator/lib.rs
@@ -0,0 +1,101 @@
+// 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.
+
+#![feature(rustc_private)]
+
+extern crate rustc;
+extern crate rustc_errors;
+extern crate syntax;
+extern crate syntax_pos;
+
+pub mod expand;
+
+pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
+    AllocatorMethod {
+        name: "alloc",
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "oom",
+        inputs: &[AllocatorTy::AllocErr],
+        output: AllocatorTy::Bang,
+        is_unsafe: false,
+    },
+    AllocatorMethod {
+        name: "dealloc",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
+        output: AllocatorTy::Unit,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "usable_size",
+        inputs: &[AllocatorTy::LayoutRef],
+        output: AllocatorTy::UsizePair,
+        is_unsafe: false,
+    },
+    AllocatorMethod {
+        name: "realloc",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "alloc_zeroed",
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "alloc_excess",
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultExcess,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "realloc_excess",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultExcess,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "grow_in_place",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultUnit,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "shrink_in_place",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultUnit,
+        is_unsafe: true,
+    },
+];
+
+pub struct AllocatorMethod {
+    pub name: &'static str,
+    pub inputs: &'static [AllocatorTy],
+    pub output: AllocatorTy,
+    pub is_unsafe: bool,
+}
+
+pub enum AllocatorTy {
+    AllocErr,
+    Bang,
+    Layout,
+    LayoutRef,
+    Ptr,
+    ResultExcess,
+    ResultPtr,
+    ResultUnit,
+    Unit,
+    UsizePair,
+}
diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml
index 0fda2805feac8..8f8ef1cc4a011 100644
--- a/src/librustc_asan/Cargo.toml
+++ b/src/librustc_asan/Cargo.toml
@@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" }
 cmake = "0.1.18"
 
 [dependencies]
+alloc = { path = "../liballoc" }
 alloc_system = { path = "../liballoc_system" }
 core = { path = "../libcore" }
diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs
index 54941362e8450..e987b1f335e19 100644
--- a/src/librustc_asan/lib.rs
+++ b/src/librustc_asan/lib.rs
@@ -11,6 +11,8 @@
 #![sanitizer_runtime]
 #![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
@@ -18,3 +20,10 @@
             issue = "0")]
 
 extern crate alloc_system;
+
+#[cfg(not(stage0))]
+use alloc_system::System;
+
+#[cfg(not(stage0))]
+#[global_allocator]
+static ALLOC: System = System;
diff --git a/src/librustc_back/target/aarch64_unknown_freebsd.rs b/src/librustc_back/target/aarch64_unknown_freebsd.rs
index c5cfff0be03ad..c5427a13e4c7d 100644
--- a/src/librustc_back/target/aarch64_unknown_freebsd.rs
+++ b/src/librustc_back/target/aarch64_unknown_freebsd.rs
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(128);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "aarch64-unknown-freebsd".to_string(),
diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
index 043bd881c7290..7c2c45a2843a7 100644
--- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(128);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs
index 62418e68d4341..5c4e01886a434 100644
--- a/src/librustc_back/target/bitrig_base.rs
+++ b/src/librustc_back/target/bitrig_base.rs
@@ -19,7 +19,6 @@ pub fn opts() -> TargetOptions {
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
-        exe_allocation_crate: "alloc_system".to_string(),
 
         .. Default::default()
     }
diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs
index c6207cdc4d9c1..63ccd21c220f3 100644
--- a/src/librustc_back/target/fuchsia_base.rs
+++ b/src/librustc_back/target/fuchsia_base.rs
@@ -37,7 +37,6 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         pre_link_args: args,
         position_independent_executables: true,
-        exe_allocation_crate: "alloc_system".to_string(),
         has_elf_tls: true,
         .. Default::default()
     }
diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
index 038a70ed6b17e..2d77902046109 100644
--- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
+++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(64),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
index aed4c4fbb08de..c26780b9e65ce 100644
--- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
+++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(64),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs
index 9ef61f9caddcd..24649851d76fd 100644
--- a/src/librustc_back/target/mips_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs
index f54790bab970b..6303722945c9f 100644
--- a/src/librustc_back/target/mips_unknown_linux_musl.rs
+++ b/src/librustc_back/target/mips_unknown_linux_musl.rs
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         }
diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs
index 59c07efe0fdc1..1a7a56a977921 100644
--- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs
+++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
index ec19cc1a536ad..cbf8339993c86 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs
index 00085d18e6d09..b367bce75a1d9 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         }
diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs
index b3ca2edec1eda..686dfbe987d10 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 5df227e39acbd..983a98e350c6a 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -378,9 +378,8 @@ pub struct TargetOptions {
     /// `eh_unwind_resume` lang item.
     pub custom_unwind_resume: bool,
 
-    /// Default crate for allocation symbols to link against
-    pub lib_allocation_crate: String,
-    pub exe_allocation_crate: String,
+    /// If necessary, a different crate to link exe allocators by default
+    pub exe_allocation_crate: Option<String>,
 
     /// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for
     /// this target.
@@ -457,8 +456,7 @@ impl Default for TargetOptions {
             link_env: Vec::new(),
             archive_format: "gnu".to_string(),
             custom_unwind_resume: false,
-            lib_allocation_crate: "alloc_system".to_string(),
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
             allow_asm: true,
             has_elf_tls: false,
             obj_is_bitcode: false,
@@ -682,8 +680,7 @@ impl Target {
         key!(archive_format);
         key!(allow_asm, bool);
         key!(custom_unwind_resume, bool);
-        key!(lib_allocation_crate);
-        key!(exe_allocation_crate);
+        key!(exe_allocation_crate, optional);
         key!(has_elf_tls, bool);
         key!(obj_is_bitcode, bool);
         key!(no_integrated_as, bool);
@@ -869,7 +866,6 @@ impl ToJson for Target {
         target_option_val!(archive_format);
         target_option_val!(allow_asm);
         target_option_val!(custom_unwind_resume);
-        target_option_val!(lib_allocation_crate);
         target_option_val!(exe_allocation_crate);
         target_option_val!(has_elf_tls);
         target_option_val!(obj_is_bitcode);
@@ -889,10 +885,10 @@ impl ToJson for Target {
     }
 }
 
-fn maybe_jemalloc() -> String {
+fn maybe_jemalloc() -> Option<String> {
     if cfg!(feature = "jemalloc") {
-        "alloc_jemalloc".to_string()
+        Some("alloc_jemalloc".to_string())
     } else {
-        "alloc_system".to_string()
+        None
     }
 }
diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs
index 2df9b8e03ff53..051028d5c4a77 100644
--- a/src/librustc_back/target/openbsd_base.rs
+++ b/src/librustc_back/target/openbsd_base.rs
@@ -34,7 +34,6 @@ pub fn opts() -> TargetOptions {
         is_like_openbsd: true,
         pre_link_args: args,
         position_independent_executables: true,
-        exe_allocation_crate: "alloc_system".to_string(),
         .. Default::default()
     }
 }
diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
index 55a5bfd1e6746..718a79a685e06 100644
--- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
@@ -18,7 +18,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
index c22bc3b041a4e..5b50b96837fbe 100644
--- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
@@ -18,7 +18,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
index 677d198b1a379..8d4ad5f0b447f 100644
--- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
@@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(32);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_back/target/redox_base.rs
index f26a86d4bdc0f..2eae0a1240823 100644
--- a/src/librustc_back/target/redox_base.rs
+++ b/src/librustc_back/target/redox_base.rs
@@ -36,8 +36,6 @@ pub fn opts() -> TargetOptions {
         eliminate_frame_pointer: false,
         target_family: None,
         linker_is_gnu: true,
-        lib_allocation_crate: "alloc_system".to_string(),
-        exe_allocation_crate: "alloc_system".to_string(),
         has_elf_tls: true,
         panic_strategy: PanicStrategy::Abort,
         .. Default::default()
diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs
index cc8eb7c4e8424..78a6bb7933d95 100644
--- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs
@@ -21,7 +21,7 @@ pub fn target() -> TargetResult {
     base.features = "-vector".to_string();
     base.max_atomic_width = Some(64);
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "s390x-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs
index 1bd51ac62581f..7f710ad402053 100644
--- a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "sparc64-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index 421f59aea93bf..c07321e418e64 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -63,7 +63,6 @@ pub fn opts() -> TargetOptions {
         is_like_windows: true,
         is_like_msvc: true,
         pre_link_args: args,
-        exe_allocation_crate: "alloc_system".to_string(),
 
         .. Default::default()
     }
diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
index eea4389cfd64e..ec5cc197dfc1a 100644
--- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
@@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
     base.position_independent_executables = false;
     base.disable_redzone = true;
     base.no_default_libraries = false;
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "x86_64-rumprun-netbsd".to_string(),
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 2e949f48c175e..f1bdf0b2c3d37 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -13,8 +13,8 @@ arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
 log = { version = "0.3", features = ["release_max_level_info"] }
 env_logger = { version = "0.4", default-features = false }
-proc_macro_plugin = { path = "../libproc_macro_plugin" }
 rustc = { path = "../librustc" }
+rustc_allocator = { path = "../librustc_allocator" }
 rustc_back = { path = "../librustc_back" }
 rustc_borrowck = { path = "../librustc_borrowck" }
 rustc_const_eval = { path = "../librustc_const_eval" }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index a3e1cf7c1a8f8..daa5917cf324d 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -27,6 +27,7 @@ use rustc::traits;
 use rustc::util::common::{ErrorReported, time};
 use rustc::util::nodemap::NodeSet;
 use rustc::util::fs::rename_or_copy_remove;
+use rustc_allocator as allocator;
 use rustc_borrowck as borrowck;
 use rustc_incremental::{self, IncrementalHashesMap};
 use rustc_resolve::{MakeGlobMap, Resolver};
@@ -750,6 +751,13 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         });
     }
 
+    krate = time(time_passes, "creating allocators", || {
+        allocator::expand::modify(&sess.parse_sess,
+                                  &mut resolver,
+                                  krate,
+                                  sess.diagnostic())
+    });
+
     after_expand(&krate)?;
 
     if sess.opts.debugging_opts.input_stats {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f2aacbc629fad..1f9f6aad90536 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -34,6 +34,7 @@ extern crate graphviz;
 extern crate env_logger;
 extern crate libc;
 extern crate rustc;
+extern crate rustc_allocator;
 extern crate rustc_back;
 extern crate rustc_borrowck;
 extern crate rustc_const_eval;
@@ -84,10 +85,11 @@ use std::cmp::max;
 use std::cmp::Ordering::Equal;
 use std::default::Default;
 use std::env;
+use std::ffi::OsString;
 use std::io::{self, Read, Write};
 use std::iter::repeat;
 use std::path::PathBuf;
-use std::process;
+use std::process::{self, Command, Stdio};
 use std::rc::Rc;
 use std::str;
 use std::sync::{Arc, Mutex};
@@ -343,6 +345,31 @@ pub trait CompilerCalls<'a> {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
+// FIXME remove these and use winapi 0.3 instead
+// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
+#[cfg(unix)]
+fn stdout_isatty() -> bool {
+    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
+}
+
+#[cfg(windows)]
+fn stdout_isatty() -> bool {
+    type DWORD = u32;
+    type BOOL = i32;
+    type HANDLE = *mut u8;
+    type LPDWORD = *mut u32;
+    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+    extern "system" {
+        fn GetStdHandle(which: DWORD) -> HANDLE;
+        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
+    }
+    unsafe {
+        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+        let mut out = 0;
+        GetConsoleMode(handle, &mut out) != 0
+    }
+}
+
 fn handle_explain(code: &str,
                   descriptions: &errors::registry::Registry,
                   output: ErrorOutputType) {
@@ -354,6 +381,8 @@ fn handle_explain(code: &str,
     match descriptions.find_description(&normalised) {
         Some(ref description) => {
             let mut is_in_code_block = false;
+            let mut text = String::new();
+
             // Slice off the leading newline and print.
             for line in description[1..].lines() {
                 let indent_level = line.find(|c: char| !c.is_whitespace())
@@ -361,12 +390,19 @@ fn handle_explain(code: &str,
                 let dedented_line = &line[indent_level..];
                 if dedented_line.starts_with("```") {
                     is_in_code_block = !is_in_code_block;
-                    println!("{}", &line[..(indent_level+3)]);
+                    text.push_str(&line[..(indent_level+3)]);
                 } else if is_in_code_block && dedented_line.starts_with("# ") {
                     continue;
                 } else {
-                    println!("{}", line);
+                    text.push_str(line);
                 }
+                text.push('\n');
+            }
+
+            if stdout_isatty() {
+                show_content_with_pager(&text);
+            } else {
+                print!("{}", text);
             }
         }
         None => {
@@ -375,6 +411,39 @@ fn handle_explain(code: &str,
     }
 }
 
+fn show_content_with_pager(content: &String) {
+    let pager_name = env::var_os("PAGER").unwrap_or_else(|| if cfg!(windows) {
+        OsString::from("more.com")
+    } else {
+        OsString::from("less")
+    });
+
+    let mut fallback_to_println = false;
+
+    match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
+        Ok(mut pager) => {
+            if let Some(mut pipe) = pager.stdin.as_mut() {
+                if pipe.write_all(content.as_bytes()).is_err() {
+                    fallback_to_println = true;
+                }
+            }
+
+            if pager.wait().is_err() {
+                fallback_to_println = true;
+            }
+        }
+        Err(_) => {
+            fallback_to_println = true;
+        }
+    }
+
+    // If pager fails for whatever reason, we should still print the content
+    // to standard output
+    if fallback_to_println {
+        print!("{}", content);
+    }
+}
+
 impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
     fn early_callback(&mut self,
                       matches: &getopts::Matches,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 2b33150902532..02d68a41b4cc4 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1071,7 +1071,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
             hir::ItemFn(.., ref generics, _) => {
-                if attr::contains_name(&it.attrs, "no_mangle") {
+                if attr::contains_name(&it.attrs, "no_mangle") &&
+                   !attr::contains_name(&it.attrs, "linkage") {
                     if !cx.access_levels.is_reachable(it.id) {
                         let msg = format!("function {} is marked #[no_mangle], but not exported",
                                           it.name);
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 770d16e5c029a..9f0ee95b5a60e 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -698,6 +698,7 @@ extern "C" {
     pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool;
     pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool);
     pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef;
+    pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool);
 
     // Operations on functions
     pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef;
diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml
index 786883d21350b..087c316211943 100644
--- a/src/librustc_lsan/Cargo.toml
+++ b/src/librustc_lsan/Cargo.toml
@@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" }
 cmake = "0.1.18"
 
 [dependencies]
+alloc = { path = "../liballoc" }
 alloc_system = { path = "../liballoc_system" }
 core = { path = "../libcore" }
diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs
index 54941362e8450..e987b1f335e19 100644
--- a/src/librustc_lsan/lib.rs
+++ b/src/librustc_lsan/lib.rs
@@ -11,6 +11,8 @@
 #![sanitizer_runtime]
 #![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
@@ -18,3 +20,10 @@
             issue = "0")]
 
 extern crate alloc_system;
+
+#[cfg(not(stage0))]
+use alloc_system::System;
+
+#[cfg(not(stage0))]
+#[global_allocator]
+static ALLOC: System = System;
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 27c2d22168c8b..ac39da48ac1fc 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -16,6 +16,7 @@ use schema::{CrateRoot, Tracked};
 
 use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
+use rustc::middle::allocator::AllocatorKind;
 use rustc::middle::cstore::DepKind;
 use rustc::session::Session;
 use rustc::session::config::{Sanitizer, self};
@@ -40,6 +41,7 @@ use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
 use syntax::feature_gate::{self, GateIssue};
 use syntax::symbol::Symbol;
+use syntax::visit;
 use syntax_pos::{Span, DUMMY_SP};
 use log;
 
@@ -920,34 +922,28 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn inject_allocator_crate(&mut self) {
-        // Make sure that we actually need an allocator, if none of our
-        // dependencies need one then we definitely don't!
-        //
-        // Also, if one of our dependencies has an explicit allocator, then we
-        // also bail out as we don't need to implicitly inject one.
-        let mut needs_allocator = false;
-        let mut found_required_allocator = false;
+    fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
+        let has_global_allocator = has_global_allocator(krate);
+        if has_global_allocator {
+            self.sess.has_global_allocator.set(true);
+        }
+
+        // Check to see if we actually need an allocator. This desire comes
+        // about through the `#![needs_allocator]` attribute and is typically
+        // written down in liballoc.
+        let mut needs_allocator = attr::contains_name(&krate.attrs,
+                                                      "needs_allocator");
         let dep_graph = &self.sess.dep_graph;
-        self.cstore.iter_crate_data(|cnum, data| {
+        self.cstore.iter_crate_data(|_, data| {
             needs_allocator = needs_allocator || data.needs_allocator(dep_graph);
-            if data.is_allocator(dep_graph) {
-                info!("{} required by rlib and is an allocator", data.name());
-                self.inject_dependency_if(cnum, "an allocator",
-                                          &|data| data.needs_allocator(dep_graph));
-                found_required_allocator = found_required_allocator ||
-                    data.dep_kind.get() == DepKind::Explicit;
-            }
         });
-        if !needs_allocator || found_required_allocator { return }
+        if !needs_allocator {
+            return
+        }
 
-        // At this point we've determined that we need an allocator and no
-        // previous allocator has been activated. We look through our outputs of
-        // crate types to see what kind of allocator types we may need.
-        //
-        // The main special output type here is that rlibs do **not** need an
-        // allocator linked in (they're just object files), only final products
-        // (exes, dylibs, staticlibs) need allocators.
+        // At this point we've determined that we need an allocator. Let's see
+        // if our compilation session actually needs an allocator based on what
+        // we're emitting.
         let mut need_lib_alloc = false;
         let mut need_exe_alloc = false;
         for ct in self.sess.crate_types.borrow().iter() {
@@ -960,44 +956,132 @@ impl<'a> CrateLoader<'a> {
                 config::CrateTypeRlib => {}
             }
         }
-        if !need_lib_alloc && !need_exe_alloc { return }
+        if !need_lib_alloc && !need_exe_alloc {
+            return
+        }
 
-        // The default allocator crate comes from the custom target spec, and we
-        // choose between the standard library allocator or exe allocator. This
-        // distinction exists because the default allocator for binaries (where
-        // the world is Rust) is different than library (where the world is
-        // likely *not* Rust).
-        //
-        // If a library is being produced, but we're also flagged with `-C
-        // prefer-dynamic`, then we interpret this as a *Rust* dynamic library
-        // is being produced so we use the exe allocator instead.
+        // Ok, we need an allocator. Not only that but we're actually going to
+        // create an artifact that needs one linked in. Let's go find the one
+        // that we're going to link in.
         //
-        // What this boils down to is:
-        //
-        // * Binaries use jemalloc
-        // * Staticlibs and Rust dylibs use system malloc
-        // * Rust dylibs used as dependencies to rust use jemalloc
-        let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
-            Symbol::intern(&self.sess.target.target.options.lib_allocation_crate)
+        // First up we check for global allocators. Look at the crate graph here
+        // and see what's a global allocator, including if we ourselves are a
+        // global allocator.
+        let dep_graph = &self.sess.dep_graph;
+        let mut global_allocator = if has_global_allocator {
+            Some(None)
         } else {
-            Symbol::intern(&self.sess.target.target.options.exe_allocation_crate)
+            None
         };
-        let dep_kind = DepKind::Implicit;
-        let (cnum, data) =
-            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
+        self.cstore.iter_crate_data(|_, data| {
+            if !data.has_global_allocator(dep_graph) {
+                return
+            }
+            match global_allocator {
+                Some(Some(other_crate)) => {
+                    self.sess.err(&format!("the #[global_allocator] in {} \
+                                            conflicts with this global \
+                                            allocator in: {}",
+                                           other_crate,
+                                           data.name()));
+                }
+                Some(None) => {
+                    self.sess.err(&format!("the #[global_allocator] in this \
+                                            crate conflicts with global \
+                                            allocator in: {}", data.name()));
+                }
+                None => global_allocator = Some(Some(data.name())),
+            }
+        });
+        if global_allocator.is_some() {
+            self.sess.allocator_kind.set(Some(AllocatorKind::Global));
+            return
+        }
+
+        // Ok we haven't found a global allocator but we still need an
+        // allocator. At this point we'll either fall back to the "library
+        // allocator" or the "exe allocator" depending on a few variables. Let's
+        // figure out which one.
+        //
+        // Note that here we favor linking to the "library allocator" as much as
+        // possible. If we're not creating rustc's version of libstd
+        // (need_lib_alloc and prefer_dynamic) then we select `None`, and if the
+        // exe allocation crate doesn't exist for this target then we also
+        // select `None`.
+        let exe_allocation_crate =
+            if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
+                None
+            } else {
+                self.sess.target.target.options.exe_allocation_crate.as_ref()
+            };
+
+        match exe_allocation_crate {
+            // We've determined that we're injecting an "exe allocator" which
+            // means that we're going to load up a whole new crate. An example
+            // of this is that we're producing a normal binary on Linux which
+            // means we need to load the `alloc_jemalloc` crate to link as an
+            // allocator.
+            Some(krate) => {
+                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultExe));
+                let name = Symbol::intern(krate);
+                let dep_kind = DepKind::Implicit;
+                let (cnum, _data) =
+                    self.resolve_crate(&None,
+                                       name,
+                                       name,
+                                       None,
+                                       DUMMY_SP,
+                                       PathKind::Crate, dep_kind);
+                self.sess.injected_allocator.set(Some(cnum));
+            //     self.cstore.iter_crate_data(|_, data| {
+            //         if !data.needs_allocator(dep_graph) {
+            //             return
+            //         }
+            //         data.cnum_map.borrow_mut().push(cnum);
+            //     });
+            }
 
-        // Sanity check the crate we loaded to ensure that it is indeed an
-        // allocator.
-        if !data.is_allocator(dep_graph) {
-            self.sess.err(&format!("the allocator crate `{}` is not tagged \
-                                    with #![allocator]", data.name()));
+            // We're not actually going to inject an allocator, we're going to
+            // require that something in our crate graph is the default lib
+            // allocator. This is typically libstd, so this'll rarely be an
+            // error.
+            None => {
+                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
+                let mut found_lib_allocator =
+                    attr::contains_name(&krate.attrs, "default_lib_allocator");
+                self.cstore.iter_crate_data(|_, data| {
+                    if !found_lib_allocator {
+                        if data.has_default_lib_allocator(dep_graph) {
+                            found_lib_allocator = true;
+                        }
+                    }
+                });
+                if found_lib_allocator {
+                    return
+                }
+                self.sess.err("no #[default_lib_allocator] found but one is \
+                               required; is libstd not linked?");
+            }
         }
 
-        self.sess.injected_allocator.set(Some(cnum));
-        self.inject_dependency_if(cnum, "an allocator",
-                                  &|data| data.needs_allocator(dep_graph));
+        fn has_global_allocator(krate: &ast::Crate) -> bool {
+            struct Finder(bool);
+            let mut f = Finder(false);
+            visit::walk_crate(&mut f, krate);
+            return f.0;
+
+            impl<'ast> visit::Visitor<'ast> for Finder {
+                fn visit_item(&mut self, i: &'ast ast::Item) {
+                    if attr::contains_name(&i.attrs, "global_allocator") {
+                        self.0 = true;
+                    }
+                    visit::walk_item(self, i)
+                }
+            }
+        }
     }
 
+
     fn inject_dependency_if(&self,
                             krate: CrateNum,
                             what: &str,
@@ -1123,7 +1207,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         // sanitizers force the use of the `alloc_system` allocator
         self.inject_sanitizer_runtime();
         self.inject_profiler_runtime();
-        self.inject_allocator_crate();
+        self.inject_allocator_crate(krate);
         self.inject_panic_runtime(krate);
 
         if log_enabled!(log::LogLevel::Info) {
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 86146fe3947bc..fb43f91c46d7f 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -275,16 +275,27 @@ impl CrateMetadata {
         self.root.disambiguator
     }
 
-    pub fn is_allocator(&self, dep_graph: &DepGraph) -> bool {
-        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
-        attr::contains_name(&attrs, "allocator")
-    }
-
     pub fn needs_allocator(&self, dep_graph: &DepGraph) -> bool {
         let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
         attr::contains_name(&attrs, "needs_allocator")
     }
 
+    pub fn has_global_allocator(&self, dep_graph: &DepGraph) -> bool {
+        let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate);
+        self.root
+            .has_global_allocator
+            .get(dep_graph, dep_node)
+            .clone()
+    }
+
+    pub fn has_default_lib_allocator(&self, dep_graph: &DepGraph) -> bool {
+        let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate);
+        self.root
+            .has_default_lib_allocator
+            .get(dep_graph, dep_node)
+            .clone()
+    }
+
     pub fn is_panic_runtime(&self, dep_graph: &DepGraph) -> bool {
         let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
         attr::contains_name(&attrs, "panic_runtime")
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 502eab44dac52..86db6fa1f90ce 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -33,6 +33,7 @@ use std::rc::Rc;
 
 use syntax::ast;
 use syntax::attr;
+use syntax::ext::base::SyntaxExtension;
 use syntax::parse::filemap_to_stream;
 use syntax::symbol::Symbol;
 use syntax_pos::{Span, NO_EXPANSION};
@@ -134,7 +135,6 @@ provide! { <'tcx> tcx, def_id, cdata,
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
 
     dylib_dependency_formats => { Rc::new(cdata.get_dylib_dependency_formats(&tcx.dep_graph)) }
-    is_allocator => { cdata.is_allocator(&tcx.dep_graph) }
     is_panic_runtime => { cdata.is_panic_runtime(&tcx.dep_graph) }
     extern_crate => { Rc::new(cdata.extern_crate.get()) }
 }
@@ -365,6 +365,10 @@ impl CrateStore for cstore::CStore {
         let data = self.get_crate_data(id.krate);
         if let Some(ref proc_macros) = data.proc_macros {
             return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize() - 1].1.clone());
+        } else if data.name == "proc_macro" &&
+                  self.get_crate_data(id.krate).item_name(id.index) == "quote" {
+            let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter));
+            return LoadedMacro::ProcMacro(Rc::new(ext));
         }
 
         let (name, def) = data.get_macro(id.index);
@@ -372,7 +376,7 @@ impl CrateStore for cstore::CStore {
 
         let filemap = sess.parse_sess.codemap().new_filemap(source_name, def.body);
         let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION };
-        let body = filemap_to_stream(&sess.parse_sess, filemap);
+        let body = filemap_to_stream(&sess.parse_sess, filemap, None);
 
         // Mark the attrs as used
         let attrs = data.get_item_attrs(id.index, &self.dep_graph);
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 3e6d06ec86ff8..ad3a9dd9fefaf 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -472,7 +472,7 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    fn item_name(&self, item_index: DefIndex) -> ast::Name {
+    pub fn item_name(&self, item_index: DefIndex) -> ast::Name {
         self.def_key(item_index)
             .disambiguated_data
             .data
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e9701b95002d4..5d73abc3ee8b8 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -400,12 +400,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tcx = self.tcx;
         let link_meta = self.link_meta;
         let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
+        let has_default_lib_allocator =
+            attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator");
+        let has_global_allocator = tcx.sess.has_global_allocator.get();
         let root = self.lazy(&CrateRoot {
             name: tcx.crate_name(LOCAL_CRATE),
             triple: tcx.sess.opts.target_triple.clone(),
             hash: link_meta.crate_hash,
             disambiguator: tcx.sess.local_crate_disambiguator(),
             panic_strategy: Tracked::new(tcx.sess.panic_strategy()),
+            has_global_allocator: Tracked::new(has_global_allocator),
+            has_default_lib_allocator: Tracked::new(has_default_lib_allocator),
             plugin_registrar_fn: tcx.sess
                 .plugin_registrar_fn
                 .get()
@@ -1129,6 +1134,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
     /// Serialize the text of exported macros
     fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> {
         use syntax::print::pprust;
+        let def_id = self.tcx.hir.local_def_id(macro_def.id);
         Entry {
             kind: EntryKind::MacroDef(self.lazy(&MacroDef {
                 body: pprust::tts_to_string(&macro_def.body.trees().collect::<Vec<_>>()),
@@ -1136,11 +1142,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
             })),
             visibility: self.lazy(&ty::Visibility::Public),
             span: self.lazy(&macro_def.span),
-
             attributes: self.encode_attributes(&macro_def.attrs),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
             children: LazySeq::empty(),
-            stability: None,
-            deprecation: None,
             ty: None,
             inherent_impls: LazySeq::empty(),
             variances: LazySeq::empty(),
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 9ef5b9408303d..0b670121ba23b 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -243,6 +243,8 @@ pub struct CrateRoot {
     pub hash: hir::svh::Svh,
     pub disambiguator: Symbol,
     pub panic_strategy: Tracked<PanicStrategy>,
+    pub has_global_allocator: Tracked<bool>,
+    pub has_default_lib_allocator: Tracked<bool>,
     pub plugin_registrar_fn: Option<DefIndex>,
     pub macro_derive_registrar: Option<DefIndex>,
 
diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml
index b3b70bc0a25ef..8d7279b29eb55 100644
--- a/src/librustc_msan/Cargo.toml
+++ b/src/librustc_msan/Cargo.toml
@@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" }
 cmake = "0.1.18"
 
 [dependencies]
+alloc = { path = "../liballoc" }
 alloc_system = { path = "../liballoc_system" }
 core = { path = "../libcore" }
diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs
index 54941362e8450..e987b1f335e19 100644
--- a/src/librustc_msan/lib.rs
+++ b/src/librustc_msan/lib.rs
@@ -11,6 +11,8 @@
 #![sanitizer_runtime]
 #![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
@@ -18,3 +20,10 @@
             issue = "0")]
 
 extern crate alloc_system;
+
+#[cfg(not(stage0))]
+use alloc_system::System;
+
+#[cfg(not(stage0))]
+#[global_allocator]
+static ALLOC: System = System;
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index a512cf2f02a5c..c7db2a9a8ae7d 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -17,6 +17,7 @@ log = "0.3"
 owning_ref = "0.3.3"
 rustc-demangle = "0.1.4"
 rustc = { path = "../librustc" }
+rustc_allocator = { path = "../librustc_allocator" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_const_math = { path = "../librustc_const_math" }
diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs
new file mode 100644
index 0000000000000..9abb6d66f9c0f
--- /dev/null
+++ b/src/librustc_trans/allocator.rs
@@ -0,0 +1,117 @@
+// 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.
+
+use std::ffi::CString;
+use std::ptr;
+
+use libc::c_uint;
+use rustc::middle::allocator::AllocatorKind;
+use rustc::ty::TyCtxt;
+use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy};
+
+use ModuleLlvm;
+use llvm::{self, False, True};
+
+pub unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
+    let llcx = mods.llcx;
+    let llmod = mods.llmod;
+    let usize = match &tcx.sess.target.target.target_pointer_width[..] {
+        "16" => llvm::LLVMInt16TypeInContext(llcx),
+        "32" => llvm::LLVMInt32TypeInContext(llcx),
+        "64" => llvm::LLVMInt64TypeInContext(llcx),
+        tws => bug!("Unsupported target word size for int: {}", tws),
+    };
+    let i8 = llvm::LLVMInt8TypeInContext(llcx);
+    let i8p = llvm::LLVMPointerType(i8, 0);
+    let usizep = llvm::LLVMPointerType(usize, 0);
+    let void = llvm::LLVMVoidTypeInContext(llcx);
+
+    for method in ALLOCATOR_METHODS {
+        let mut args = Vec::new();
+        for ty in method.inputs.iter() {
+            match *ty {
+                AllocatorTy::Layout => {
+                    args.push(usize); // size
+                    args.push(usize); // align
+                }
+                AllocatorTy::LayoutRef => args.push(i8p),
+                AllocatorTy::Ptr => args.push(i8p),
+                AllocatorTy::AllocErr => args.push(i8p),
+
+                AllocatorTy::Bang |
+                AllocatorTy::ResultExcess |
+                AllocatorTy::ResultPtr |
+                AllocatorTy::ResultUnit |
+                AllocatorTy::UsizePair |
+                AllocatorTy::Unit => panic!("invalid allocator arg"),
+            }
+        }
+        let output = match method.output {
+            AllocatorTy::UsizePair => {
+                args.push(usizep); // min
+                args.push(usizep); // max
+                None
+            }
+            AllocatorTy::Bang => None,
+            AllocatorTy::ResultExcess => {
+                args.push(i8p); // excess_ptr
+                args.push(i8p); // err_ptr
+                Some(i8p)
+            }
+            AllocatorTy::ResultPtr => {
+                args.push(i8p); // err_ptr
+                Some(i8p)
+            }
+            AllocatorTy::ResultUnit => Some(i8),
+            AllocatorTy::Unit => None,
+
+            AllocatorTy::AllocErr |
+            AllocatorTy::Layout |
+            AllocatorTy::LayoutRef |
+            AllocatorTy::Ptr => panic!("invalid allocator output"),
+        };
+        let ty = llvm::LLVMFunctionType(output.unwrap_or(void),
+                                        args.as_ptr(),
+                                        args.len() as c_uint,
+                                        False);
+        let name = CString::new(format!("__rust_{}", method.name)).unwrap();
+        let llfn = llvm::LLVMRustGetOrInsertFunction(llmod,
+                                                     name.as_ptr(),
+                                                     ty);
+
+        let callee = CString::new(kind.fn_name(method.name)).unwrap();
+        let callee = llvm::LLVMRustGetOrInsertFunction(llmod,
+                                                       callee.as_ptr(),
+                                                       ty);
+
+        let llbb = llvm::LLVMAppendBasicBlockInContext(llcx,
+                                                       llfn,
+                                                       "entry\0".as_ptr() as *const _);
+
+        let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
+        llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
+        let args = args.iter().enumerate().map(|(i, _)| {
+            llvm::LLVMGetParam(llfn, i as c_uint)
+        }).collect::<Vec<_>>();
+        let ret = llvm::LLVMRustBuildCall(llbuilder,
+                                          callee,
+                                          args.as_ptr(),
+                                          args.len() as c_uint,
+                                          ptr::null_mut(),
+                                          "\0".as_ptr() as *const _);
+        llvm::LLVMSetTailCall(ret, True);
+        if output.is_some() {
+            llvm::LLVMBuildRet(llbuilder, ret);
+        } else {
+            llvm::LLVMBuildRetVoid(llbuilder);
+        }
+        llvm::LLVMDisposeBuilder(llbuilder);
+    }
+}
diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs
index 6bef31ccf64a4..fa93c005dcd8f 100644
--- a/src/librustc_trans/attributes.rs
+++ b/src/librustc_trans/attributes.rs
@@ -13,7 +13,7 @@ use std::ffi::{CStr, CString};
 
 use llvm::{self, Attribute, ValueRef};
 use llvm::AttributePlace::Function;
-pub use syntax::attr::InlineAttr;
+pub use syntax::attr::{self, InlineAttr};
 use syntax::ast;
 use context::CrateContext;
 
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index a7f205a18a46c..a4bbdef82f094 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -55,6 +55,10 @@ pub const METADATA_MODULE_NAME: &'static str = "crate.metadata";
 /// 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";
+
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
 // Version 1
 // Bytes    Data
@@ -240,6 +244,9 @@ pub fn link_binary(sess: &Session,
             }
         }
         remove(sess, &outputs.with_extension(METADATA_OBJ_NAME));
+        if trans.allocator_module.is_some() {
+            remove(sess, &outputs.with_extension(ALLOCATOR_OBJ_NAME));
+        }
     }
 
     out_filenames
@@ -363,6 +370,24 @@ pub fn each_linked_rlib(sess: &Session,
     Ok(())
 }
 
+/// Returns a boolean indicating whether the specified crate should be ignored
+/// during LTO.
+///
+/// Crates ignored during LTO are not lumped together in the "massive object
+/// file" that we create and are linked in their normal rlib states. See
+/// comments below for what crates do not participate in LTO.
+///
+/// It's unusual for a crate to not participate in LTO. Typically only
+/// compiler-specific and unstable crates have a reason to not participate in
+/// LTO.
+pub fn ignored_for_lto(sess: &Session, cnum: CrateNum) -> bool {
+    // `#![no_builtins]` crates don't participate in LTO because the state
+    // of builtins gets messed up (our crate isn't tagged with no builtins).
+    // Similarly `#![compiler_builtins]` doesn't participate because we want
+    // those builtins!
+    sess.cstore.is_no_builtins(cnum) || sess.cstore.is_compiler_builtins(cnum)
+}
+
 fn out_filename(sess: &Session,
                 crate_type: config::CrateType,
                 outputs: &OutputFilenames,
@@ -417,11 +442,21 @@ fn link_binary_output(sess: &Session,
         let out_filename = out_filename(sess, crate_type, outputs, crate_name);
         match crate_type {
             config::CrateTypeRlib => {
-                link_rlib(sess, Some(trans), &objects, &out_filename,
+                link_rlib(sess,
+                          trans,
+                          RlibFlavor::Normal,
+                          &objects,
+                          outputs,
+                          &out_filename,
                           tmpdir.path()).build();
             }
             config::CrateTypeStaticlib => {
-                link_staticlib(sess, &objects, &out_filename, tmpdir.path());
+                link_staticlib(sess,
+                               trans,
+                               outputs,
+                               &objects,
+                               &out_filename,
+                               tmpdir.path());
             }
             _ => {
                 link_natively(sess, crate_type, &objects, &out_filename, trans,
@@ -477,6 +512,11 @@ fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename:
     }
 }
 
+enum RlibFlavor {
+    Normal,
+    StaticlibBase,
+}
+
 // Create an 'rlib'
 //
 // An rlib in its current incarnation is essentially a renamed .a file. The
@@ -484,8 +524,10 @@ fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename:
 // all of the object files from native libraries. This is done by unzipping
 // native libraries and inserting all of the contents into this archive.
 fn link_rlib<'a>(sess: &'a Session,
-                 trans: Option<&CrateTranslation>, // None == no metadata/bytecode
+                 trans: &CrateTranslation,
+                 flavor: RlibFlavor,
                  objects: &[PathBuf],
+                 outputs: &OutputFilenames,
                  out_filename: &Path,
                  tmpdir: &Path) -> ArchiveBuilder<'a> {
     info!("preparing rlib from {:?} to {:?}", objects, out_filename);
@@ -546,8 +588,8 @@ fn link_rlib<'a>(sess: &'a Session,
     //
     // Basically, all this means is that this code should not move above the
     // code above.
-    match trans {
-        Some(trans) => {
+    match flavor {
+        RlibFlavor::Normal => {
             // Instead of putting the metadata in an object file section, rlibs
             // contain the metadata in a separate file. We use a temp directory
             // here so concurrent builds in the same directory don't try to use
@@ -620,7 +662,11 @@ fn link_rlib<'a>(sess: &'a Session,
             }
         }
 
-        None => {}
+        RlibFlavor::StaticlibBase => {
+            if trans.allocator_module.is_some() {
+                ab.add_file(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+            }
+        }
     }
 
     ab
@@ -672,9 +718,19 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write,
 // There's no need to include metadata in a static archive, so ensure to not
 // link in the metadata object file (and also don't prepare the archive with a
 // metadata file).
-fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
+fn link_staticlib(sess: &Session,
+                  trans: &CrateTranslation,
+                  outputs: &OutputFilenames,
+                  objects: &[PathBuf],
+                  out_filename: &Path,
                   tempdir: &Path) {
-    let mut ab = link_rlib(sess, None, objects, out_filename, tempdir);
+    let mut ab = link_rlib(sess,
+                           trans,
+                           RlibFlavor::StaticlibBase,
+                           objects,
+                           outputs,
+                           out_filename,
+                           tempdir);
     let mut all_native_libs = vec![];
 
     let res = each_linked_rlib(sess, &mut |cnum, path| {
@@ -698,7 +754,10 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
         let skip_object_files = native_libs.iter().any(|lib| {
             lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
         });
-        ab.add_rlib(path, &name.as_str(), sess.lto(), skip_object_files).unwrap();
+        ab.add_rlib(path,
+                    &name.as_str(),
+                    sess.lto() && !ignored_for_lto(sess, cnum),
+                    skip_object_files).unwrap();
 
         all_native_libs.extend(sess.cstore.native_libraries(cnum));
     });
@@ -944,6 +1003,10 @@ fn link_args(cmd: &mut Linker,
         cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME));
     }
 
+    if trans.allocator_module.is_some() {
+        cmd.add_object(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+    }
+
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
     if !sess.opts.cg.link_dead_code {
@@ -1247,7 +1310,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
             lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
         });
 
-        if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native {
+        if (!sess.lto() || ignored_for_lto(sess, cnum)) &&
+           crate_type != config::CrateTypeDylib &&
+           !skip_native {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
             return
         }
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index b38dc18838923..52fe747858cc4 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -92,7 +92,6 @@ impl ExportedSymbols {
             // Down below we'll hardwire all of the symbols to the `Rust` export
             // level instead.
             let special_runtime_crate =
-                scx.tcx().is_allocator(cnum.as_def_id()) ||
                 scx.tcx().is_panic_runtime(cnum.as_def_id()) ||
                 scx.sess().cstore.is_compiler_builtins(cnum);
 
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 562d7171156fe..5e227ec467abb 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -644,6 +644,7 @@ pub fn run_passes(sess: &Session,
 
     let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone());
     let mut metadata_config = ModuleConfig::new(tm, vec![]);
+    let mut allocator_config = ModuleConfig::new(tm, vec![]);
 
     if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
         match *sanitizer {
@@ -674,6 +675,7 @@ pub fn run_passes(sess: &Session,
         modules_config.emit_bc = true;
         modules_config.emit_lto_bc = true;
         metadata_config.emit_bc = true;
+        allocator_config.emit_bc = true;
     }
 
     // Emit bitcode files for the crate if we're emitting an rlib.
@@ -699,6 +701,7 @@ pub fn run_passes(sess: &Session,
                 // in this case we still want the metadata object file.
                 if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
                     metadata_config.emit_obj = true;
+                    allocator_config.emit_obj = true;
                 }
             }
             OutputType::Object => { modules_config.emit_obj = true; }
@@ -706,6 +709,7 @@ pub fn run_passes(sess: &Session,
             OutputType::Exe => {
                 modules_config.emit_obj = true;
                 metadata_config.emit_obj = true;
+                allocator_config.emit_obj = true;
             },
             OutputType::Mir => {}
             OutputType::DepInfo => {}
@@ -714,6 +718,7 @@ pub fn run_passes(sess: &Session,
 
     modules_config.set_flags(sess, trans);
     metadata_config.set_flags(sess, trans);
+    allocator_config.set_flags(sess, trans);
 
 
     // Populate a buffer with a list of codegen threads.  Items are processed in
@@ -729,6 +734,14 @@ pub fn run_passes(sess: &Session,
         work_items.push(work);
     }
 
+    if let Some(allocator) = trans.allocator_module.clone() {
+        let work = build_work_item(sess,
+                                   allocator,
+                                   allocator_config.clone(),
+                                   crate_output.clone());
+        work_items.push(work);
+    }
+
     for mtrans in trans.modules.iter() {
         let work = build_work_item(sess,
                                    mtrans.clone(),
@@ -905,6 +918,13 @@ pub fn run_passes(sess: &Session,
                                               Some(&trans.metadata_module.name));
             remove(sess, &path);
         }
+        if allocator_config.emit_bc && !user_wants_bitcode {
+            if let Some(ref module) = trans.allocator_module {
+                let path = crate_output.temp_path(OutputType::Bitcode,
+                                                  Some(&module.name));
+                remove(sess, &path);
+            }
+        }
     }
 
     // We leave the following files around by default:
@@ -1200,8 +1220,7 @@ fn spawn_work<'a>(sess: &'a Session,
     let crate_types = sess.crate_types.borrow().clone();
     let mut each_linked_rlib_for_lto = Vec::new();
     drop(link::each_linked_rlib(sess, &mut |cnum, path| {
-        // `#![no_builtins]` crates don't participate in LTO.
-        if sess.cstore.is_no_builtins(cnum) {
+        if link::ignored_for_lto(sess, cnum) {
             return
         }
         each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 2589a3538a940..8298324e99680 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -47,6 +47,7 @@ use rustc::session::config::{self, NoDebugInfo, OutputFilenames};
 use rustc::session::Session;
 use rustc_incremental::IncrementalHashesMap;
 use abi;
+use allocator;
 use mir::lvalue::LvalueRef;
 use attributes;
 use builder::Builder;
@@ -1086,8 +1087,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             llmod: metadata_llmod,
         }),
     };
+
     let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
 
+
     // Skip crate items and just output metadata in -Z no-trans mode.
     if tcx.sess.opts.debugging_opts.no_trans ||
        !tcx.sess.opts.output_types.should_trans() {
@@ -1097,6 +1100,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             crate_name: tcx.crate_name(LOCAL_CRATE),
             modules: vec![],
             metadata_module: metadata_module,
+            allocator_module: None,
             link: link_meta,
             metadata: metadata,
             exported_symbols: empty_exported_symbols,
@@ -1296,6 +1300,41 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         create_imps(sess, &llvm_modules);
     }
 
+    // Translate an allocator shim, if any
+    //
+    // If LTO is enabled and we've got some previous LLVM module we translated
+    // above, then we can just translate directly into that LLVM module. If not,
+    // however, we need to create a separate module and trans into that. Note
+    // that the separate translation is critical for the standard library where
+    // the rlib's object file doesn't have allocator functions but the dylib
+    // links in an object file that has allocator functions. When we're
+    // compiling a final LTO artifact, though, there's no need to worry about
+    // this as we're not working with this dual "rlib/dylib" functionality.
+    let allocator_module = tcx.sess.allocator_kind.get().and_then(|kind| unsafe {
+        if sess.lto() && llvm_modules.len() > 0 {
+            time(tcx.sess.time_passes(), "write allocator module", || {
+                allocator::trans(tcx, &llvm_modules[0], kind)
+            });
+            None
+        } else {
+            let (llcx, llmod) =
+                context::create_context_and_module(tcx.sess, "allocator");
+            let modules = ModuleLlvm {
+                llmod: llmod,
+                llcx: llcx,
+            };
+            time(tcx.sess.time_passes(), "write allocator module", || {
+                allocator::trans(tcx, &modules, kind)
+            });
+
+            Some(ModuleTranslation {
+                name: link::ALLOCATOR_MODULE_NAME.to_string(),
+                symbol_name_hash: 0, // we always rebuild allocator shims
+                source: ModuleSource::Translated(modules),
+            })
+        }
+    });
+
     let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols);
 
     let subsystem = attr::first_attr_value_str_by_name(&krate.attrs,
@@ -1313,6 +1352,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         crate_name: tcx.crate_name(LOCAL_CRATE),
         modules: modules,
         metadata_module: metadata_module,
+        allocator_module: allocator_module,
         link: link_meta,
         metadata: metadata,
         exported_symbols: exported_symbols,
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 2787812f9622c..8f9146283effe 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -30,7 +30,6 @@ use context::CrateContext;
 use common;
 use type_::Type;
 use value::Value;
-use syntax::attr;
 
 use std::ffi::CString;
 
@@ -88,16 +87,6 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty:
         }
     }
 
-    // If we're compiling the compiler-builtins crate, e.g. the equivalent of
-    // compiler-rt, then we want to implicitly compile everything with hidden
-    // visibility as we're going to link this object all over the place but
-    // don't want the symbols to get exported.
-    if attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") {
-        unsafe {
-            llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
-        }
-    }
-
     match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) {
         Some("s") => {
             llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 6acd10cb887f8..5c76f778f8d63 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -43,6 +43,7 @@ extern crate crossbeam;
 extern crate libc;
 extern crate owning_ref;
 #[macro_use] extern crate rustc;
+extern crate rustc_allocator;
 extern crate rustc_back;
 extern crate rustc_data_structures;
 extern crate rustc_incremental;
@@ -84,6 +85,7 @@ mod diagnostics;
 
 mod abi;
 mod adt;
+mod allocator;
 mod asm;
 mod assert_module_sources;
 mod attributes;
@@ -163,6 +165,7 @@ pub struct CrateTranslation {
     pub crate_name: Symbol,
     pub modules: Vec<ModuleTranslation>,
     pub metadata_module: ModuleTranslation,
+    pub allocator_module: Option<ModuleTranslation>,
     pub link: rustc::middle::cstore::LinkMeta,
     pub metadata: rustc::middle::cstore::EncodedMetadata,
     pub exported_symbols: back::symbol_export::ExportedSymbols,
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 2a6e7c5ace6cf..200f6dee334ad 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -162,6 +162,18 @@ impl<'a, 'tcx> TransItem<'tcx> {
             llvm::SetUniqueComdat(ccx.llmod(), lldecl);
         }
 
+        // If we're compiling the compiler-builtins crate, e.g. the equivalent of
+        // compiler-rt, then we want to implicitly compile everything with hidden
+        // visibility as we're going to link this object all over the place but
+        // don't want the symbols to get exported.
+        if linkage != llvm::Linkage::InternalLinkage &&
+           linkage != llvm::Linkage::PrivateLinkage &&
+           attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") {
+            unsafe {
+                llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
+            }
+        }
+
         debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
         if common::is_inline_instance(ccx.tcx(), &instance) {
             attributes::inline(lldecl, attributes::InlineAttr::Hint);
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index de8749c43d95c..89a40b0db9662 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -319,7 +319,7 @@ impl<'a> Classifier<'a> {
             token::Lifetime(..) => Class::Lifetime,
 
             token::Underscore | token::Eof | token::Interpolated(..) |
-            token::SubstNt(..) | token::Tilde | token::At => Class::None,
+            token::Tilde | token::At => Class::None,
         };
 
         // Anything that didn't return above is the simple case where we the
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 38f83687d1d85..788cd80b075ea 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -1233,21 +1233,24 @@
         onEach(e.getElementsByClassName('associatedconstant'), func);
     });
 
-    var span = document.createElement('span');
-    span.className = 'toggle-label';
-    span.style.display = 'none';
-    span.innerHTML = '&nbsp;Expand&nbsp;description';
-
-    var mainToggle = toggle.cloneNode(true);
-    mainToggle.appendChild(span);
-
-    var wrapper = document.createElement('div');
-    wrapper.className = 'toggle-wrapper';
-    wrapper.appendChild(mainToggle);
+    function createToggle() {
+        var span = document.createElement('span');
+        span.className = 'toggle-label';
+        span.style.display = 'none';
+        span.innerHTML = '&nbsp;Expand&nbsp;description';
+
+        var mainToggle = toggle.cloneNode(true);
+        mainToggle.appendChild(span);
+
+        var wrapper = document.createElement('div');
+        wrapper.className = 'toggle-wrapper';
+        wrapper.appendChild(mainToggle);
+        return wrapper;
+    }
 
     onEach(document.getElementById('main').getElementsByClassName('docblock'), function(e) {
         if (e.parentNode.id === "main") {
-            e.parentNode.insertBefore(wrapper, e);
+            e.parentNode.insertBefore(createToggle(), e);
         }
     });
 
@@ -1273,18 +1276,22 @@
         }
     })
 
-    var span = document.createElement('span');
-    span.className = 'toggle-label';
-    span.style.display = 'none';
-    span.innerHTML = '&nbsp;Expand&nbsp;attributes';
-    toggle.appendChild(span);
+    function createToggleWrapper() {
+        var span = document.createElement('span');
+        span.className = 'toggle-label';
+        span.style.display = 'none';
+        span.innerHTML = '&nbsp;Expand&nbsp;attributes';
+        toggle.appendChild(span);
+
+        var wrapper = document.createElement('div');
+        wrapper.className = 'toggle-wrapper toggle-attributes';
+        wrapper.appendChild(toggle);
+        return wrapper;
+    }
 
-    var wrapper = document.createElement('div');
-    wrapper.className = 'toggle-wrapper toggle-attributes';
-    wrapper.appendChild(toggle);
     onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) {
         onEach(e.getElementsByClassName('attributes'), function(i_e) {
-            i_e.parentNode.insertBefore(wrapper, i_e);
+            i_e.parentNode.insertBefore(createToggleWrapper(), i_e);
             collapseDocs(i_e.previousSibling.childNodes[0]);
         });
     });
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index b516cbd08ca02..09c168169348b 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -19,7 +19,7 @@ collections = { path = "../libcollections" }
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
 rand = { path = "../librand" }
-compiler_builtins = { path = "../libcompiler_builtins" }
+compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
 profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 std_unicode = { path = "../libstd_unicode" }
 unwind = { path = "../libunwind" }
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index 50c721db849aa..06f4f7643ec83 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::heap::{allocate, deallocate};
+use alloc::heap::{Heap, Alloc, Layout};
 
 use cmp;
 use hash::{BuildHasher, Hash, Hasher};
@@ -781,10 +781,8 @@ impl<K, V> RawTable<K, V> {
                     .expect("capacity overflow"),
                 "capacity overflow");
 
-        let buffer = allocate(size, alignment);
-        if buffer.is_null() {
-            ::alloc::oom()
-        }
+        let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap())
+            .unwrap_or_else(|e| Heap.oom(e));
 
         let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
 
@@ -1193,7 +1191,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
         debug_assert!(!oflo, "should be impossible");
 
         unsafe {
-            deallocate(self.hashes.ptr() as *mut u8, size, align);
+            Heap.dealloc(self.hashes.ptr() as *mut u8,
+                         Layout::from_size_align(size, align).unwrap());
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 4b340f70fbc74..d77f817659c56 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -224,7 +224,7 @@ impl Error for ! {
 
 #[unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked.",
-           issue = "27700")]
+           issue = "32838")]
 impl Error for allocator::AllocErr {
     fn description(&self) -> &str {
         allocator::AllocErr::description(self)
@@ -233,7 +233,7 @@ impl Error for allocator::AllocErr {
 
 #[unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked.",
-           issue = "27700")]
+           issue = "32838")]
 impl Error for allocator::CannotReallocInPlace {
     fn description(&self) -> &str {
         allocator::CannotReallocInPlace::description(self)
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 7d79fb078116f..a6eb17c8fa41b 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -1131,13 +1131,16 @@ impl f32 {
     #[inline]
     pub fn from_bits(mut v: u32) -> Self {
         const EXP_MASK: u32   = 0x7F800000;
-        const QNAN_MASK: u32  = 0x00400000;
         const FRACT_MASK: u32 = 0x007FFFFF;
         if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
-            // If we have a NaN value, we
-            // convert signaling NaN values to quiet NaN
-            // by setting the the highest bit of the fraction
-            v |= QNAN_MASK;
+            // While IEEE 754-2008 specifies encodings for quiet NaNs
+            // and signaling ones, certain MIPS and PA-RISC
+            // CPUs treat signaling NaNs differently.
+            // Therefore to be safe, we pass a known quiet NaN
+            // if v is any kind of NaN.
+            // The check above only assumes IEEE 754-1985 to be
+            // valid.
+            v = unsafe { ::mem::transmute(NAN) };
         }
         unsafe { ::mem::transmute(v) }
     }
@@ -1732,8 +1735,15 @@ mod tests {
     }
     #[test]
     fn test_snan_masking() {
+        // NOTE: this test assumes that our current platform
+        // implements IEEE 754-2008 that specifies the difference
+        // in encoding of quiet and signaling NaNs.
+        // If you are porting Rust to a platform that does not
+        // implement IEEE 754-2008 (but e.g. IEEE 754-1985, which
+        // only says that "Signaling NaNs shall be reserved operands"
+        // but doesn't specify the actual setup), feel free to
+        // cfg out this test.
         let snan: u32 = 0x7F801337;
-        const PAYLOAD_MASK: u32 = 0x003FFFFF;
         const QNAN_MASK: u32  = 0x00400000;
         let nan_masked_fl = f32::from_bits(snan);
         let nan_masked = nan_masked_fl.to_bits();
@@ -1742,7 +1752,5 @@ mod tests {
         // Ensure that we have a quiet NaN
         assert_ne!(nan_masked & QNAN_MASK, 0);
         assert!(nan_masked_fl.is_nan());
-        // Ensure the payload wasn't touched during conversion
-        assert_eq!(nan_masked & PAYLOAD_MASK, snan & PAYLOAD_MASK);
     }
 }
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index d5b0cd3a1fc79..4d8d8b4ebe6aa 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -1046,13 +1046,16 @@ impl f64 {
     #[inline]
     pub fn from_bits(mut v: u64) -> Self {
         const EXP_MASK: u64   = 0x7FF0000000000000;
-        const QNAN_MASK: u64  = 0x0001000000000000;
         const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF;
         if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
-            // If we have a NaN value, we
-            // convert signaling NaN values to quiet NaN
-            // by setting the the highest bit of the fraction
-            v |= QNAN_MASK;
+            // While IEEE 754-2008 specifies encodings for quiet NaNs
+            // and signaling ones, certain MIPS and PA-RISC
+            // CPUs treat signaling NaNs differently.
+            // Therefore to be safe, we pass a known quiet NaN
+            // if v is any kind of NaN.
+            // The check above only assumes IEEE 754-1985 to be
+            // valid.
+            v = unsafe { ::mem::transmute(NAN) };
         }
         unsafe { ::mem::transmute(v) }
     }
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 1a91417ca0e92..5f0b11a616eb0 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -585,11 +585,11 @@ impl From<Box<CStr>> for CString {
     }
 }
 
-#[stable(feature = "box_from_c_string", since = "1.18.0")]
-impl Into<Box<CStr>> for CString {
+#[stable(feature = "box_from_c_string", since = "1.20.0")]
+impl From<CString> for Box<CStr> {
     #[inline]
-    fn into(self) -> Box<CStr> {
-        self.into_boxed_c_str()
+    fn from(s: CString) -> Box<CStr> {
+        s.into_boxed_c_str()
     }
 }
 
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 42d641706a894..02a13ed7a5a03 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -540,10 +540,10 @@ impl From<Box<OsStr>> for OsString {
     }
 }
 
-#[stable(feature = "box_from_os_string", since = "1.18.0")]
-impl Into<Box<OsStr>> for OsString {
-    fn into(self) -> Box<OsStr> {
-        self.into_boxed_os_str()
+#[stable(feature = "box_from_os_string", since = "1.20.0")]
+impl From<OsString> for Box<OsStr> {
+    fn from(s: OsString) -> Box<OsStr> {
+        s.into_boxed_os_str()
     }
 }
 
diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs
new file mode 100644
index 0000000000000..83bd3b04b4de2
--- /dev/null
+++ b/src/libstd/heap.rs
@@ -0,0 +1,165 @@
+// 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.
+
+//! dox
+
+#![unstable(issue = "32838", feature = "allocator_api")]
+
+pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr};
+#[cfg(not(stage0))]
+pub use alloc_system::System;
+
+#[cfg(all(not(stage0), not(test)))]
+#[doc(hidden)]
+pub mod __default_lib_allocator {
+    use super::{System, Layout, Alloc, AllocErr};
+    use ptr;
+
+    // for symbol names src/librustc/middle/allocator.rs
+    // for signatures src/librustc_allocator/lib.rs
+
+    // linkage directives are provided as part of the current compiler allocator
+    // ABI
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_alloc(size: usize,
+                                     align: usize,
+                                     err: *mut u8) -> *mut u8 {
+        let layout = Layout::from_size_align_unchecked(size, align);
+        match System.alloc(layout) {
+            Ok(p) => p,
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_oom(err: *const u8) -> ! {
+        System.oom((*(err as *const AllocErr)).clone())
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
+                                       size: usize,
+                                       align: usize) {
+        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_usable_size(layout: *const u8,
+                                           min: *mut usize,
+                                           max: *mut usize) {
+        let pair = System.usable_size(&*(layout as *const Layout));
+        *min = pair.0;
+        *max = pair.1;
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
+                                       old_size: usize,
+                                       old_align: usize,
+                                       new_size: usize,
+                                       new_align: usize,
+                                       err: *mut u8) -> *mut u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.realloc(ptr, old_layout, new_layout) {
+            Ok(p) => p,
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_alloc_zeroed(size: usize,
+                                            align: usize,
+                                            err: *mut u8) -> *mut u8 {
+        let layout = Layout::from_size_align_unchecked(size, align);
+        match System.alloc_zeroed(layout) {
+            Ok(p) => p,
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_alloc_excess(size: usize,
+                                            align: usize,
+                                            excess: *mut usize,
+                                            err: *mut u8) -> *mut u8 {
+        let layout = Layout::from_size_align_unchecked(size, align);
+        match System.alloc_excess(layout) {
+            Ok(p) => {
+                *excess = p.1;
+                p.0
+            }
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8,
+                                              old_size: usize,
+                                              old_align: usize,
+                                              new_size: usize,
+                                              new_align: usize,
+                                              excess: *mut usize,
+                                              err: *mut u8) -> *mut u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.realloc_excess(ptr, old_layout, new_layout) {
+            Ok(p) => {
+                *excess = p.1;
+                p.0
+            }
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8,
+                                             old_size: usize,
+                                             old_align: usize,
+                                             new_size: usize,
+                                             new_align: usize) -> u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.grow_in_place(ptr, old_layout, new_layout) {
+            Ok(()) => 1,
+            Err(_) => 0,
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8,
+                                               old_size: usize,
+                                               old_align: usize,
+                                               new_size: usize,
+                                               new_align: usize) -> u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.shrink_in_place(ptr, old_layout, new_layout) {
+            Ok(()) => 1,
+            Err(_) => 0,
+        }
+    }
+}
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index bafe23e80a030..c4bdf7c5b822b 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -230,11 +230,6 @@
 // Tell the compiler to link to either panic_abort or panic_unwind
 #![needs_panic_runtime]
 
-// Always use alloc_system during stage0 since we don't know if the alloc_*
-// crate the stage0 compiler will pick by default is available (most
-// obviously, if the user has disabled jemalloc in `./configure`).
-#![cfg_attr(any(stage0, feature = "force_alloc_system"), feature(alloc_system))]
-
 // Turn warnings into errors, but only after stage0, where it can be useful for
 // code to emit warnings during language transitions
 #![deny(warnings)]
@@ -246,6 +241,8 @@
 // compiler details that will never be stable
 #![feature(alloc)]
 #![feature(allocator_api)]
+#![feature(alloc_system)]
+#![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
 #![feature(asm)]
 #![feature(associated_consts)]
@@ -322,6 +319,8 @@
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(test, feature(float_bits_conv))]
 
+#![cfg_attr(not(stage0), default_lib_allocator)]
+
 // Explicitly import the prelude. The compiler uses this same unstable attribute
 // to import the prelude implicitly when building crates that depend on std.
 #[prelude_import]
@@ -342,15 +341,13 @@ extern crate core as __core;
 #[macro_use]
 #[macro_reexport(vec, format)]
 extern crate alloc;
+extern crate alloc_system;
 extern crate std_unicode;
 extern crate libc;
 
 // We always need an unwinder currently for backtraces
 extern crate unwind;
 
-#[cfg(any(stage0, feature = "force_alloc_system"))]
-extern crate alloc_system;
-
 // compiler-rt intrinsics
 extern crate compiler_builtins;
 
@@ -465,6 +462,7 @@ pub mod path;
 pub mod process;
 pub mod sync;
 pub mod time;
+pub mod heap;
 
 // Platform-abstraction modules
 #[macro_use]
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 472ce6bc4fe9e..e7c7be981d25f 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1348,10 +1348,10 @@ impl From<Box<Path>> for PathBuf {
     }
 }
 
-#[stable(feature = "box_from_path_buf", since = "1.18.0")]
-impl Into<Box<Path>> for PathBuf {
-    fn into(self) -> Box<Path> {
-        self.into_boxed_path()
+#[stable(feature = "box_from_path_buf", since = "1.20.0")]
+impl From<PathBuf> for Box<Path> {
+    fn from(p: PathBuf) -> Box<Path> {
+        p.into_boxed_path()
     }
 }
 
diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs
index 48d9cdcb2c937..c5a19e8debe93 100644
--- a/src/libstd/sys/redox/fs.rs
+++ b/src/libstd/sys/redox/fs.rs
@@ -420,12 +420,19 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    canonicalize(p)
-}
-
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
-    ::sys_common::util::dumb_print(format_args!("Symlink\n"));
-    unimplemented!();
+    let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_SYMLINK | syscall::O_RDONLY))?;
+    let mut buf: [u8; 4096] = [0; 4096];
+    let count = cvt(syscall::read(fd, &mut buf))?;
+    cvt(syscall::close(fd))?;
+    Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+    let fd = cvt(syscall::open(dst.to_str().unwrap(),
+                               syscall::O_SYMLINK | syscall::O_CREAT | syscall::O_WRONLY | 0o777))?;
+    cvt(syscall::write(fd, src.to_str().unwrap().as_bytes()))?;
+    cvt(syscall::close(fd))?;
+    Ok(())
 }
 
 pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
diff --git a/src/libstd/sys/redox/syscall/flag.rs b/src/libstd/sys/redox/syscall/flag.rs
index 9f0d3e6f77955..bd603cfe6ef9d 100644
--- a/src/libstd/sys/redox/syscall/flag.rs
+++ b/src/libstd/sys/redox/syscall/flag.rs
@@ -33,6 +33,7 @@ pub const MAP_WRITE_COMBINE: usize = 2;
 pub const MODE_TYPE: u16 = 0xF000;
 pub const MODE_DIR: u16 = 0x4000;
 pub const MODE_FILE: u16 = 0x8000;
+pub const MODE_SYMLINK: u16 = 0xA000;
 
 pub const MODE_PERM: u16 = 0x0FFF;
 pub const MODE_SETUID: u16 = 0o4000;
@@ -53,6 +54,7 @@ pub const O_TRUNC: usize =      0x0400_0000;
 pub const O_EXCL: usize =       0x0800_0000;
 pub const O_DIRECTORY: usize =  0x1000_0000;
 pub const O_STAT: usize =       0x2000_0000;
+pub const O_SYMLINK: usize =    0x4000_0000;
 pub const O_ACCMODE: usize =    O_RDONLY | O_WRONLY | O_RDWR;
 
 pub const SEEK_SET: usize = 0;
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 854d380d128c9..46e5acdf3d22b 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -59,8 +59,6 @@ pub mod stdio;
 
 #[cfg(not(test))]
 pub fn init() {
-    use alloc::oom;
-
     // By default, some platforms will send a *signal* when an EPIPE error
     // would otherwise be delivered. This runtime doesn't install a SIGPIPE
     // handler, causing it to kill the program, which isn't exactly what we
@@ -72,24 +70,6 @@ pub fn init() {
         reset_sigpipe();
     }
 
-    oom::set_oom_handler(oom_handler);
-
-    // A nicer handler for out-of-memory situations than the default one. This
-    // one prints a message to stderr before aborting. It is critical that this
-    // code does not allocate any memory since we are in an OOM situation. Any
-    // errors are ignored while printing since there's nothing we can do about
-    // them and we are about to exit anyways.
-    fn oom_handler() -> ! {
-        use intrinsics;
-        let msg = "fatal runtime error: out of memory\n";
-        unsafe {
-            libc::write(libc::STDERR_FILENO,
-                        msg.as_ptr() as *const libc::c_void,
-                        msg.len());
-            intrinsics::abort();
-        }
-    }
-
     #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 840e7fdfc9b26..ee58efc5144a8 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -47,24 +47,6 @@ pub mod stdio;
 
 #[cfg(not(test))]
 pub fn init() {
-    ::alloc::oom::set_oom_handler(oom_handler);
-
-    // See comment in sys/unix/mod.rs
-    fn oom_handler() -> ! {
-        use intrinsics;
-        use ptr;
-        let msg = "fatal runtime error: out of memory\n";
-        unsafe {
-            // WriteFile silently fails if it is passed an invalid handle, so
-            // there is no need to check the result of GetStdHandle.
-            c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE),
-                         msg.as_ptr() as c::LPVOID,
-                         msg.len() as c::DWORD,
-                         ptr::null_mut(),
-                         ptr::null_mut());
-            intrinsics::abort();
-        }
-    }
 }
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
diff --git a/src/libstd_unicode/tables.rs b/src/libstd_unicode/tables.rs
index 7173040350ed9..0938738b52cbd 100644
--- a/src/libstd_unicode/tables.rs
+++ b/src/libstd_unicode/tables.rs
@@ -14,7 +14,7 @@
 
 /// The version of [Unicode](http://www.unicode.org/)
 /// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on.
-pub const UNICODE_VERSION: (u64, u64, u64) = (9, 0, 0);
+pub const UNICODE_VERSION: (u64, u64, u64) = (10, 0, 0);
 
 
 // BoolTrie is a trie for representing a set of Unicode codepoints. It is
@@ -167,7 +167,7 @@ pub mod general_category {
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0,
             0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
+            0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
             11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -236,7 +236,7 @@ pub mod derived_property {
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102,
-            103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36,
+            103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 95, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
@@ -244,23 +244,23 @@ pub mod derived_property {
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
             36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-            36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119,
+            36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 117, 118,
             31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
             31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
             31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
             31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
             31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
             31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-            36, 36, 36, 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128,
-            129, 31, 130, 36, 131, 132, 133, 113, 134
+            36, 36, 36, 36, 36, 119, 36, 120, 121, 122, 123, 124, 36, 36, 36, 36, 125, 126, 127,
+            128, 31, 129, 36, 130, 131, 132, 113, 133
         ],
         r3: &[
-            0x00001ffffcffffff, 0x0000000001ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000,
-            0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x0003000fb080599f,
-            0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x0200000f00011bbf,
+            0x00001ffffcffffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000,
+            0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x1003000fb080599f,
+            0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x1e00000f00011bbf,
             0xe3edfdfffff99fee, 0x0002000fb0c0199f, 0xc3ffc718d63dc7ec, 0x0000000000811dc7,
             0xe3fffdfffffddfef, 0x0000000f07601ddf, 0xe3effdfffffddfef, 0x0006000f40601ddf,
-            0xe7fffffffffddfee, 0xfc00000f80f05ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f,
+            0xe7fffffffffddfef, 0xfc00000f80f05ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f,
             0x07fffffffffffffe, 0x000000000000207f, 0x3bffecaefef02596, 0x00000000f000205f,
             0x0000000000000001, 0xfffe1ffffffffeff, 0x1ffffffffeffff03, 0x0000000000000000,
             0xf97fffffffffffff, 0xffffc1e7ffff0000, 0xffffffff3000407f, 0xf7ffffffffff20bf,
@@ -278,74 +278,76 @@ pub mod derived_property {
             0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff,
             0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f,
             0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff,
-            0xfffe3fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff,
+            0xfffe7fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff,
             0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff,
             0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000,
             0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000002f, 0xffff07fffffffc00,
             0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff,
             0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e,
-            0xffff003ff7ffffff, 0x000007ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f,
-            0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb,
-            0x0003ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000,
-            0xfffffffffffcffff, 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff,
-            0x07fffffe00000000, 0xffffffc007fffffe, 0x000000001cfcfcfc
+            0xffff003ff7ffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, 0xffff3fffffffffff,
+            0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x0003ffffffffffff,
+            0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff,
+            0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, 0x07fffffe00000000,
+            0xffffffc007fffffe, 0x000000001cfcfcfc
         ],
         r4: [
             0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 13, 14,
-            15, 5, 5, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+            15, 7, 16, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
         ],
         r5: &[
             0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2,
             2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32,
             32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 34, 35, 32, 36, 2, 37, 38, 4, 39, 40, 41,
             42, 4, 4, 2, 43, 2, 44, 4, 4, 45, 46, 47, 48, 28, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4,
-            4, 4, 4, 4, 52, 4, 4, 4, 4, 53, 54, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 56, 4, 2, 57, 2, 2, 2, 58, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 52, 53, 54, 55, 4, 4, 4, 4, 56, 57, 58, 4, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 4, 2, 62, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 57, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 59, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2,
-            2, 2, 2, 2, 52, 20, 4, 60, 16, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 63, 64,
-            65, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2,
+            2, 2, 2, 2, 2, 2, 55, 20, 4, 65, 16, 66, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
+            68, 69, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 66, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 72, 2, 2, 2, 2, 2, 73,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 2, 68, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 2, 70, 71, 72, 73, 74, 2, 2, 2, 2, 75, 76, 77, 78, 79, 80, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 81,
+            4, 4, 4, 4, 4, 4, 4, 2, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 2, 2, 2, 82, 2, 83, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 84, 85,
-            86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 87, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 2, 2, 2, 88, 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 90, 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 72, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 4, 4, 4,
+            96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
         ],
         r6: &[
             0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff,
             0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff,
-            0xffff0000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f,
+            0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f,
             0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff,
             0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff,
             0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff,
@@ -356,17 +358,18 @@ pub mod derived_property {
             0x000001ffffffffff, 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000007bb,
             0x00000000000000b3, 0x7f3fffffffffffff, 0x000000003f000000, 0x7fffffffffffffff,
             0x0000000000000011, 0x000007ffe3ffffff, 0xffffffff00000000, 0x80000000ffffffff,
-            0x01ffffffffffffff, 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff,
-            0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f,
-            0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, 0x7fffffffffff001f,
-            0x00000000fff80000, 0x0000000100000000, 0x00001fffffffffff, 0x0000000000000003,
-            0x1fff07ffffffffff, 0x0000000043ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff,
-            0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff,
-            0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff,
-            0x0000000000000ff7, 0x000007dbf9ffff7f, 0x000000000000001f, 0x000000000000008f,
-            0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0xffff000000000000,
-            0xffff03ffffff03ff, 0x00000000000003ff, 0x00000000007fffff, 0x00000003ffffffff,
-            0x000000003fffffff
+            0x7fe7ffffffffffff, 0xffffffffffff0000, 0x0000000000ffffcf, 0x01ffffffffffffff,
+            0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, 0xb47ffffffffffb7f,
+            0x00000000000000cb, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f,
+            0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff,
+            0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff,
+            0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000043ff01ff,
+            0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf,
+            0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff,
+            0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000007dbf9ffff7f,
+            0x000000000000001f, 0x000000000000008f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84,
+            0x0ffffbee0ffffbff, 0xffff03ffffff03ff, 0x00000000000003ff, 0x00000000007fffff,
+            0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff
         ],
     };
 
@@ -426,9 +429,9 @@ pub mod derived_property {
         r3: &[
             0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff00000,
             0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e,
-            0x1000000000000006, 0x0023000000023986, 0x0000000c000021be, 0x9000000000000002,
+            0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002,
             0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001,
-            0x0000000c00603dc1, 0x0000000c00003040, 0x0000000000000002, 0x00000000005c0400,
+            0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400,
             0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40,
             0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040,
             0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000,
@@ -437,7 +440,7 @@ pub mod derived_property {
             0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000,
             0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000,
             0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000,
-            0x010007ffffffffff, 0xfffffffff8000000, 0xf83fffffffffffff, 0xa000000000000000,
+            0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, 0xa000000000000000,
             0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000,
             0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000,
             0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000,
@@ -465,24 +468,24 @@ pub mod derived_property {
             0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20,
-            0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 27, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0,
+            0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,
-            2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 42, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 48, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45,
-            0, 0, 45, 45, 45, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0
+            50, 51, 0, 0, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0
         ],
         r6: &[
             0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000,
@@ -491,12 +494,14 @@ pub mod derived_property {
             0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003,
             0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000,
             0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000,
-            0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0xbf7f000000000000,
-            0x006dfcfffffc0000, 0x001f000000000000, 0x007f000000000000, 0x000000000000000f,
-            0x00000000ffff8000, 0x0000000f60000000, 0xfff8038000000000, 0x00003c0000000fe7,
-            0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010,
-            0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xf800000000000000,
-            0xffffffff00000002, 0xffffffffffffffff, 0x0000ffffffffffff
+            0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e,
+            0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000,
+            0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000,
+            0x000000000000000f, 0x00000000ffff8000, 0x0000000300000000, 0x0000000f60000000,
+            0xfff8038000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff,
+            0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000,
+            0x00000000000007f0, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff,
+            0x0000ffffffffffff
         ],
     };
 
@@ -851,12 +856,12 @@ pub mod derived_property {
             127
         ],
         r3: &[
-            0x00003fffffffffff, 0x000000000fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000,
-            0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x0003ffcfb080799f,
-            0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0x0200ffcf00013bbf,
+            0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000,
+            0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x1003ffcfb080799f,
+            0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf,
             0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7,
             0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf,
-            0xe7fffffffffddfee, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f,
+            0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f,
             0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f,
             0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040,
             0xffffffffffff03ff, 0xffffffff3fffffff, 0xf7ffffffffff20bf, 0xffffffff3d7f3dff,
@@ -867,13 +872,13 @@ pub mod derived_property {
             0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff,
             0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff,
             0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff,
-            0x00000000000001ff, 0x037ffffffff70000, 0xf83fffffffffffff, 0xffffffff3f3fffff,
+            0x00000000000001ff, 0x03fffffffff70000, 0xfbffffffffffffff, 0xffffffff3f3fffff,
             0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000,
             0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84,
             0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff,
             0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f,
-            0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0,
-            0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, 0x0000000000001fff,
+            0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0,
+            0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff,
             0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff,
             0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff,
             0x28ffffff03ff003f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001,
@@ -886,60 +891,62 @@ pub mod derived_property {
         ],
         r4: [
             0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13,
-            14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+            14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-            5, 5, 5, 5, 5, 5, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+            5, 5, 5, 5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
         ],
         r5: &[
             0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2,
             2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33,
             33, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 34, 3, 35, 36, 37, 2, 38, 39, 4, 40, 41, 42,
             43, 4, 4, 2, 44, 2, 45, 4, 4, 46, 47, 2, 48, 49, 50, 51, 4, 4, 4, 4, 4, 52, 53, 4, 4, 4,
-            4, 4, 4, 4, 54, 4, 4, 4, 4, 55, 56, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 58, 4, 2, 59, 2, 2, 2, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 4, 2, 64, 2, 2, 2, 65, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 59, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 61, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2,
-            2, 2, 2, 2, 54, 62, 4, 63, 17, 64, 65, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 66, 67,
-            68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2,
+            2, 2, 2, 2, 2, 2, 57, 67, 4, 68, 17, 69, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
+            71, 72, 73, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 75, 2, 2, 2, 2, 2, 76,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 2, 71, 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 73, 74, 4, 4,
-            75, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, 4, 4,
-            4, 4, 4, 4, 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 2, 2, 2, 91, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            92, 93, 94, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            4, 4, 4, 4, 4, 4, 4, 2, 77, 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            79, 80, 4, 4, 81, 4, 4, 4, 4, 4, 4, 2, 82, 83, 84, 85, 86, 2, 2, 2, 2, 87, 88, 89, 90,
+            91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 4, 4, 4, 4, 4, 4, 4,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
         ],
         r6: &[
             0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff,
             0x0000000000000000, 0x001fffffffffffff, 0x2000000000000000, 0xffffffff1fffffff,
-            0x000000010001ffff, 0xffff0000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff,
+            0x000000010001ffff, 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff,
             0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff,
             0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f,
             0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff,
@@ -950,18 +957,20 @@ pub mod derived_property {
             0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f,
             0x0000000003ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001,
             0x0000000003ff0011, 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe3ffffff,
-            0xffffffff00000000, 0x800003ffffffffff, 0x01ffffffffffffff, 0xff7ffffffffffdff,
-            0xfffc000003ff0001, 0x007ffefffffcffff, 0x0000000003ffffff, 0x00007fffffffffff,
-            0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, 0x001f3fffffff0000,
-            0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, 0x00000000ffff8000,
-            0x0000000100000000, 0x00001fffffffffff, 0x0000000000000003, 0x1fff07ffffffffff,
-            0x0000000063ff01ff, 0xf807e3e000000000, 0x00003c0000000fe7, 0x000000000000001c,
-            0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf,
-            0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff,
-            0xffff7fffffff7fff, 0xfffffdfffffffdff, 0xffffffffffffcff7, 0xf87fffffffffffff,
-            0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f001f,
-            0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff,
-            0x00000003ffffffff, 0x000000003fffffff, 0x0000ffffffffffff
+            0xffffffff00000000, 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080,
+            0x0000000003ffffcf, 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001,
+            0x007ffefffffcffff, 0xb47ffffffffffb7f, 0x0000000003ff00ff, 0x0000000003ffffff,
+            0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff,
+            0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f,
+            0x00000000ffff8000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000,
+            0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000,
+            0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff,
+            0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff,
+            0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff,
+            0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010,
+            0x000007dbf9ffff7f, 0x00000000007f001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84,
+            0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff,
+            0x000000003fffffff, 0x0000ffffffffffff
         ],
     };
 
@@ -1027,8 +1036,8 @@ pub mod derived_property {
             129, 130, 131, 132
         ],
         r3: &[
-            0x00000110043fffff, 0x0000000001ffffff, 0x3fdfffff00000000, 0x0000000000000000,
-            0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x00030003b0004000,
+            0x00000110043fffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0x0000000000000000,
+            0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x10030003b0004000,
             0x036dfdfffff987e0, 0x001c00005e000000, 0x23edfdfffffbbfe0, 0x0200000300010000,
             0x23edfdfffff99fe0, 0x00020003b0000000, 0x03ffc718d63dc7e8, 0x0000000000010000,
             0x23fffdfffffddfe0, 0x0000000307000000, 0x23effdfffffddfe1, 0x0006000340000000,
@@ -1048,8 +1057,8 @@ pub mod derived_property {
             0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84,
             0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff,
             0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f,
-            0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0,
-            0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, 0x0000000000001fff,
+            0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0,
+            0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff,
             0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff,
             0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000,
             0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00,
@@ -1064,58 +1073,60 @@ pub mod derived_property {
         ],
         r4: [
             0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13,
-            14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+            14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
         ],
         r5: &[
             0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2,
             2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32,
             32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 33, 4, 34, 35, 36, 37, 38, 39, 40, 4, 41, 20,
             42, 43, 4, 4, 5, 44, 45, 46, 4, 4, 47, 48, 45, 49, 50, 4, 51, 4, 4, 4, 4, 4, 52, 53, 4,
-            4, 4, 4, 4, 4, 4, 54, 4, 4, 4, 4, 55, 56, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 58, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 63, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 59, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2,
-            2, 2, 2, 2, 2, 2, 54, 20, 4, 60, 45, 61, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2,
-            62, 63, 64, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 2, 67, 68, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 69, 70, 71, 72, 73, 2, 2, 2, 2, 74, 75, 76, 77, 78, 79, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            2, 2, 2, 2, 2, 2, 2, 2, 57, 20, 4, 65, 45, 66, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 2, 67, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 71, 2, 2, 2, 2, 2,
+            72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 2, 73, 74, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 75, 76, 77, 78, 79, 2, 2, 2, 2, 80, 81, 82, 83, 84,
+            85, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4, 4, 2, 2, 2, 80, 2, 58, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            81, 82, 83, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 84, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 86, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 4, 4, 4, 4, 4, 4, 4,
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 2, 2, 2, 2, 2, 2, 2, 2, 86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-            4, 4, 4, 4
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
         ],
         r6: &[
             0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff,
             0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff,
-            0xffff0000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f,
+            0xffffe000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f,
             0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff,
             0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff,
             0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff,
@@ -1126,15 +1137,17 @@ pub mod derived_property {
             0x00000ffffffbffff, 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000,
             0x0000000000000780, 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff,
             0x000000000f000000, 0x0000000000000010, 0x000007ffffffffff, 0x0000000003ffffff,
-            0xffffffff00000000, 0x80000000ffffffff, 0x01ffffffffffffff, 0x00007ffffffffdff,
-            0xfffc000000000001, 0x000000000000ffff, 0x000000000000000f, 0x000000000000007f,
-            0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, 0x00000000fff80000,
-            0x0000000100000000, 0x00001fffffffffff, 0x0000000000000003, 0x1fff07ffffffffff,
-            0x0000000003ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef,
-            0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd,
-            0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7,
-            0x000000000000001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff,
-            0x00000000007fffff, 0x00000003ffffffff, 0x000000003fffffff
+            0xffffffff00000000, 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000,
+            0x00000000000003cf, 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001,
+            0x000000000000ffff, 0x0001fffffffffb7f, 0x0000000000000040, 0x000000000000000f,
+            0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f,
+            0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000,
+            0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff,
+            0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f,
+            0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff,
+            0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef,
+            0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff,
+            0x00000001ffffffff, 0x000000003fffffff
         ],
     };
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ecab801d40853..d00e29d954fc6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -99,7 +99,7 @@ impl Path {
     pub fn default_to_global(mut self) -> Path {
         if !self.is_global() &&
            !::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() {
-            self.segments.insert(0, PathSegment::crate_root());
+            self.segments.insert(0, PathSegment::crate_root(self.span));
         }
         self
     }
@@ -133,10 +133,10 @@ impl PathSegment {
     pub fn from_ident(ident: Ident, span: Span) -> Self {
         PathSegment { identifier: ident, span: span, parameters: None }
     }
-    pub fn crate_root() -> Self {
+    pub fn crate_root(span: Span) -> Self {
         PathSegment {
-            identifier: keywords::CrateRoot.ident(),
-            span: DUMMY_SP,
+            identifier: Ident { ctxt: span.ctxt, ..keywords::CrateRoot.ident() },
+            span: span,
             parameters: None,
         }
     }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 8e63e219c42c1..f0fc849c0c596 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -1057,7 +1057,7 @@ impl MetaItem {
     {
         let (mut span, name) = match tokens.next() {
             Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name),
-            Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt {
+            Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match nt.0 {
                 token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name),
                 token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
                 _ => return None,
@@ -1229,7 +1229,7 @@ impl LitKind {
         match token {
             Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)),
             Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)),
-            Token::Interpolated(ref nt) => match **nt {
+            Token::Interpolated(ref nt) => match nt.0 {
                 token::NtExpr(ref v) => match v.node {
                     ExprKind::Lit(ref lit) => Some(lit.node.clone()),
                     _ => None,
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 8089fad5f36d8..4881170c1d13a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -215,7 +215,7 @@ impl<F> TTMacroExpander for F
         impl Folder for AvoidInterpolatedIdents {
             fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree {
                 if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt {
-                    if let token::NtIdent(ident) = **nt {
+                    if let token::NtIdent(ident) = nt.0 {
                         return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node));
                     }
                 }
@@ -578,7 +578,10 @@ impl SyntaxExtension {
 
     pub fn is_modern(&self) -> bool {
         match *self {
-            SyntaxExtension::DeclMacro(..) => true,
+            SyntaxExtension::DeclMacro(..) |
+            SyntaxExtension::ProcMacro(..) |
+            SyntaxExtension::AttrProcMacro(..) |
+            SyntaxExtension::ProcMacroDerive(..) => true,
             _ => false,
         }
     }
@@ -903,17 +906,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
     }
     Some(es)
 }
-
-pub struct ChangeSpan {
-    pub span: Span
-}
-
-impl Folder for ChangeSpan {
-    fn new_span(&mut self, _sp: Span) -> Span {
-        self.span
-    }
-
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        fold::noop_fold_mac(mac, self)
-    }
-}
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 412a34932087d..03e5ea529e210 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -249,6 +249,8 @@ pub trait AstBuilder {
                 name: Ident, attrs: Vec<ast::Attribute>,
                 items: Vec<P<ast::Item>>) -> P<ast::Item>;
 
+    fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item>;
+
     fn item_static(&self,
                    span: Span,
                    name: Ident,
@@ -320,7 +322,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let last_identifier = idents.pop().unwrap();
         let mut segments: Vec<ast::PathSegment> = Vec::new();
         if global {
-            segments.push(ast::PathSegment::crate_root());
+            segments.push(ast::PathSegment::crate_root(sp));
         }
 
         segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, sp)));
@@ -1095,6 +1097,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         )
     }
 
+    fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item> {
+        self.item(span, name, Vec::new(), ast::ItemKind::ExternCrate(None))
+    }
+
     fn item_static(&self,
                    span: Span,
                    name: Ident,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index f8a26287bd47b..d2e51c9cb4868 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -16,20 +16,20 @@ use config::{is_test_or_bench, StripUnconfigured};
 use errors::FatalError;
 use ext::base::*;
 use ext::derive::{add_derived_markers, collect_derives};
-use ext::hygiene::Mark;
+use ext::hygiene::{Mark, SyntaxContext};
 use ext::placeholders::{placeholder, PlaceholderExpander};
 use feature_gate::{self, Features, is_builtin_attr};
 use fold;
 use fold::*;
-use parse::{filemap_to_stream, ParseSess, DirectoryOwnership, PResult, token};
+use parse::{DirectoryOwnership, PResult};
+use parse::token::{self, Token};
 use parse::parser::Parser;
-use print::pprust;
 use ptr::P;
 use std_inject;
 use symbol::Symbol;
 use symbol::keywords;
 use syntax_pos::{Span, DUMMY_SP};
-use tokenstream::TokenStream;
+use tokenstream::{TokenStream, TokenTree};
 use util::small_vector::SmallVector;
 use visit::Visitor;
 
@@ -427,11 +427,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 kind.expect_from_annotatables(items)
             }
             SyntaxExtension::AttrProcMacro(ref mac) => {
-                let item_toks = stream_for_item(&item, self.cx.parse_sess);
-
-                let span = Span { ctxt: self.cx.backtrace(), ..attr.span };
-                let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks);
-                self.parse_expansion(tok_result, kind, &attr.path, span)
+                let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
+                    Annotatable::Item(item) => token::NtItem(item),
+                    Annotatable::TraitItem(item) => token::NtTraitItem(item.unwrap()),
+                    Annotatable::ImplItem(item) => token::NtImplItem(item.unwrap()),
+                })).into();
+                let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
+                self.parse_expansion(tok_result, kind, &attr.path, attr.span)
             }
             SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
                 self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
@@ -470,7 +472,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             Ok(())
         };
 
-        let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
         let opt_expanded = match *ext {
             SyntaxExtension::DeclMacro(ref expand, def_span) => {
                 if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
@@ -478,7 +479,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     self.cx.span_err(path.span, &msg);
                     return kind.dummy(span);
                 }
-                kind.make_from(expand.expand(self.cx, span, marked_tts))
+                kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
             }
 
             NormalTT(ref expandfun, def_info, allow_internal_unstable) => {
@@ -487,7 +488,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     self.cx.span_err(path.span, &msg);
                     return kind.dummy(span);
                 }
-                kind.make_from(expandfun.expand(self.cx, span, marked_tts))
+                kind.make_from(expandfun.expand(self.cx, span, mac.node.stream()))
             }
 
             IdentTT(ref expander, tt_span, allow_internal_unstable) => {
@@ -506,7 +507,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                 });
 
-                let input: Vec<_> = marked_tts.into_trees().collect();
+                let input: Vec<_> = mac.node.stream().into_trees().collect();
                 kind.make_from(expander.expand(self.cx, span, ident, input))
             }
 
@@ -541,21 +542,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     },
                 });
 
-                let tok_result = expandfun.expand(self.cx, span, marked_tts);
+                let tok_result = expandfun.expand(self.cx, span, mac.node.stream());
                 Some(self.parse_expansion(tok_result, kind, path, span))
             }
         };
 
-        let expanded = if let Some(expanded) = opt_expanded {
-            expanded
-        } else {
+        unwrap_or!(opt_expanded, {
             let msg = format!("non-{kind} macro in {kind} position: {name}",
                               name = path.segments[0].identifier.name, kind = kind.name());
             self.cx.span_err(path.span, &msg);
-            return kind.dummy(span);
-        };
-
-        expanded.fold_with(&mut Marker(mark))
+            kind.dummy(span)
+        })
     }
 
     /// Expand a derive invocation. Returns the result of expansion.
@@ -621,8 +618,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
         };
         parser.ensure_complete_parse(path, kind.name(), span);
-        // FIXME better span info
-        expansion.fold_with(&mut ChangeSpan { span: span })
+        expansion
     }
 }
 
@@ -673,7 +669,9 @@ impl<'a> Parser<'a> {
         if self.token != token::Eof {
             let msg = format!("macro expansion ignores token `{}` and any following",
                               self.this_token_to_string());
-            let mut err = self.diagnostic().struct_span_err(self.span, &msg);
+            let mut def_site_span = self.span;
+            def_site_span.ctxt = SyntaxContext::empty(); // Avoid emitting backtrace info twice.
+            let mut err = self.diagnostic().struct_span_err(def_site_span, &msg);
             let msg = format!("caused by the macro expansion here; the usage \
                                of `{}!` is likely invalid in {} context",
                                macro_path, kind_name);
@@ -773,28 +771,6 @@ pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute
          .map(|i| attrs.remove(i))
 }
 
-// These are pretty nasty. Ideally, we would keep the tokens around, linked from
-// the AST. However, we don't so we need to create new ones. Since the item might
-// have come from a macro expansion (possibly only in part), we can't use the
-// existing codemap.
-//
-// Therefore, we must use the pretty printer (yuck) to turn the AST node into a
-// string, which we then re-tokenise (double yuck), but first we have to patch
-// the pretty-printed string on to the end of the existing codemap (infinity-yuck).
-fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream {
-    let text = match *item {
-        Annotatable::Item(ref i) => pprust::item_to_string(i),
-        Annotatable::TraitItem(ref ti) => pprust::trait_item_to_string(ti),
-        Annotatable::ImplItem(ref ii) => pprust::impl_item_to_string(ii),
-    };
-    string_to_stream(text, parse_sess)
-}
-
-fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream {
-    let filename = String::from("<macro expansion>");
-    filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text))
-}
-
 impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
         let mut expr = self.cfg.configure_expr(expr).unwrap();
@@ -1070,7 +1046,7 @@ impl<'feat> ExpansionConfig<'feat> {
 }
 
 // A Marker adds the given mark to the syntax context.
-struct Marker(Mark);
+pub struct Marker(pub Mark);
 
 impl Folder for Marker {
     fn fold_ident(&mut self, mut ident: Ident) -> Ident {
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index f8fac847a053e..9907dfe341e75 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -30,9 +30,9 @@ pub mod rt {
     use ast;
     use codemap::Spanned;
     use ext::base::ExtCtxt;
-    use parse::{self, token, classify};
+    use parse::{self, classify};
+    use parse::token::{self, Token};
     use ptr::P;
-    use std::rc::Rc;
     use symbol::Symbol;
 
     use tokenstream::{self, TokenTree, TokenStream};
@@ -82,70 +82,70 @@ pub mod rt {
     impl ToTokens for ast::Path {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtPath(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::Ty {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtTy(P(self.clone()));
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::Block {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtBlock(P(self.clone()));
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::Generics {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtGenerics(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::WhereClause {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtWhereClause(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for P<ast::Item> {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtItem(self.clone());
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::ImplItem {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtImplItem(self.clone());
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for P<ast::ImplItem> {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtImplItem((**self).clone());
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::TraitItem {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtTraitItem(self.clone());
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::Stmt {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtStmt(self.clone());
-            let mut tts = vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))];
+            let mut tts = vec![TokenTree::Token(self.span, Token::interpolated(nt))];
 
             // Some statements require a trailing semicolon.
             if classify::stmt_ends_with_semi(&self.node) {
@@ -159,35 +159,35 @@ pub mod rt {
     impl ToTokens for P<ast::Expr> {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtExpr(self.clone());
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for P<ast::Pat> {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtPat(self.clone());
-            vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(self.span, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::Arm {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtArm(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for ast::Arg {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtArg(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
     impl ToTokens for P<ast::Block> {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtBlock(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
@@ -215,7 +215,7 @@ pub mod rt {
     impl ToTokens for ast::MetaItem {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
             let nt = token::NtMeta(self.clone());
-            vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
+            vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
         }
     }
 
@@ -364,7 +364,7 @@ pub mod rt {
 
         fn parse_tts(&self, s: String) -> Vec<TokenTree> {
             let source_name = "<quote expansion>".to_owned();
-            parse::parse_stream_from_source_str(source_name, s, self.parse_sess())
+            parse::parse_stream_from_source_str(source_name, s, self.parse_sess(), None)
                 .into_trees().collect()
         }
     }
@@ -700,7 +700,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
         token::Underscore   => "Underscore",
         token::Eof          => "Eof",
 
-        token::Whitespace | token::SubstNt(_) | token::Comment | token::Shebang(_) => {
+        token::Whitespace | token::Comment | token::Shebang(_) => {
             panic!("unhandled token in quote!");
         }
     };
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 61d8fc2941afb..e877f1fedd409 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -158,15 +158,10 @@ pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
 pub fn count_names(ms: &[TokenTree]) -> usize {
     ms.iter().fold(0, |count, elt| {
         count + match *elt {
-            TokenTree::Sequence(_, ref seq) => {
-                seq.num_captures
-            }
-            TokenTree::Delimited(_, ref delim) => {
-                count_names(&delim.tts)
-            }
-            TokenTree::MetaVarDecl(..) => {
-                1
-            }
+            TokenTree::Sequence(_, ref seq) => seq.num_captures,
+            TokenTree::Delimited(_, ref delim) => count_names(&delim.tts),
+            TokenTree::MetaVar(..) => 0,
+            TokenTree::MetaVarDecl(..) => 1,
             TokenTree::Token(..) => 0,
         }
     })
@@ -244,7 +239,7 @@ fn nameize<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, ms: &[TokenTree], mut
                     }
                 }
             }
-            TokenTree::Token(..) => (),
+            TokenTree::MetaVar(..) | TokenTree::Token(..) => (),
         }
 
         Ok(())
@@ -409,12 +404,11 @@ fn inner_parse_loop(sess: &ParseSess,
                     ei.idx = 0;
                     cur_eis.push(ei);
                 }
-                TokenTree::Token(_, ref t) => {
-                    if token_name_eq(t, token) {
-                        ei.idx += 1;
-                        next_eis.push(ei);
-                    }
+                TokenTree::Token(_, ref t) if token_name_eq(t, token) => {
+                    ei.idx += 1;
+                    next_eis.push(ei);
                 }
+                TokenTree::Token(..) | TokenTree::MetaVar(..) => {}
             }
         }
     }
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 9c728c9f2ebf0..b732f47ce6a93 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -120,7 +120,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
                     _ => cx.span_bug(sp, "malformed macro rhs"),
                 };
                 // rhs has holes ( `$id` and `$(...)` that need filled)
-                let tts = transcribe(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
+                let tts = transcribe(cx, Some(named_matches), rhs);
 
                 if cx.trace_macros() {
                     trace_macros_note(cx, sp, format!("to `{}`", tts));
@@ -292,7 +292,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
     use self::quoted::TokenTree;
     for tt in tts {
         match *tt {
-            TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => (),
+            TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
             TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) {
                 return false;
             },
@@ -372,7 +372,7 @@ impl FirstSets {
             let mut first = TokenSet::empty();
             for tt in tts.iter().rev() {
                 match *tt {
-                    TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
+                    TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
                         first.replace_with(tt.clone());
                     }
                     TokenTree::Delimited(span, ref delimited) => {
@@ -432,7 +432,7 @@ impl FirstSets {
         for tt in tts.iter() {
             assert!(first.maybe_empty);
             match *tt {
-                TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
+                TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
                     first.add_one(tt.clone());
                     return first;
                 }
@@ -602,7 +602,7 @@ fn check_matcher_core(sess: &ParseSess,
         // First, update `last` so that it corresponds to the set
         // of NT tokens that might end the sequence `... token`.
         match *token {
-            TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
+            TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
                 let can_be_followed_by_any;
                 if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, token) {
                     let msg = format!("invalid fragment specifier `{}`", bad_frag);
@@ -872,6 +872,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess,
 fn quoted_tt_to_string(tt: &quoted::TokenTree) -> String {
     match *tt {
         quoted::TokenTree::Token(_, ref tok) => ::print::pprust::token_to_string(tok),
+        quoted::TokenTree::MetaVar(_, name) => format!("${}", name),
         quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
         _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} \
                      in follow set checker"),
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index c094a23cefc4a..4e9e30857b1e8 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -78,9 +78,11 @@ pub enum KleeneOp {
 pub enum TokenTree {
     Token(Span, token::Token),
     Delimited(Span, Rc<Delimited>),
-    /// A kleene-style repetition sequence with a span
+    /// A kleene-style repetition sequence
     Sequence(Span, Rc<SequenceRepetition>),
-    /// Matches a nonterminal. This is only used in the left hand side of MBE macros.
+    /// E.g. `$var`
+    MetaVar(Span, ast::Ident),
+    /// E.g. `$var:expr`. This is only used in the left hand side of MBE macros.
     MetaVarDecl(Span, ast::Ident /* name to bind */, ast::Ident /* kind of nonterminal */),
 }
 
@@ -130,6 +132,7 @@ impl TokenTree {
     pub fn span(&self) -> Span {
         match *self {
             TokenTree::Token(sp, _) |
+            TokenTree::MetaVar(sp, _) |
             TokenTree::MetaVarDecl(sp, _, _) |
             TokenTree::Delimited(sp, _) |
             TokenTree::Sequence(sp, _) => sp,
@@ -144,7 +147,7 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars
     while let Some(tree) = trees.next() {
         let tree = parse_tree(tree, &mut trees, expect_matchers, sess);
         match tree {
-            TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => {
+            TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
                 let span = match trees.next() {
                     Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() {
                         Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() {
@@ -199,13 +202,13 @@ fn parse_tree<I>(tree: tokenstream::TokenTree,
                     let ident = ast::Ident { name: keywords::DollarCrate.name(), ..ident };
                     TokenTree::Token(span, token::Ident(ident))
                 } else {
-                    TokenTree::Token(span, token::SubstNt(ident))
+                    TokenTree::MetaVar(span, ident)
                 }
             }
             Some(tokenstream::TokenTree::Token(span, tok)) => {
                 let msg = format!("expected identifier, found `{}`", pprust::token_to_string(&tok));
                 sess.span_diagnostic.span_err(span, &msg);
-                TokenTree::Token(span, token::SubstNt(keywords::Invalid.ident()))
+                TokenTree::MetaVar(span, keywords::Invalid.ident())
             }
             None => TokenTree::Token(span, token::Dollar),
         },
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 78e755e73fa30..fe3dd83f9d5c0 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -9,10 +9,12 @@
 // except according to those terms.
 
 use ast::Ident;
-use errors::Handler;
+use ext::base::ExtCtxt;
+use ext::expand::Marker;
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
 use ext::tt::quoted;
-use parse::token::{self, SubstNt, Token, NtTT};
+use fold::noop_fold_tt;
+use parse::token::{self, Token, NtTT};
 use syntax_pos::{Span, DUMMY_SP};
 use tokenstream::{TokenStream, TokenTree, Delimited};
 use util::small_vector::SmallVector;
@@ -61,9 +63,9 @@ impl Iterator for Frame {
 }
 
 /// This can do Macro-By-Example transcription. On the other hand, if
-/// `src` contains no `TokenTree::{Sequence, Match}`s, or `SubstNt`s, `interp` can
+/// `src` contains no `TokenTree::{Sequence, MetaVar, MetaVarDecl}`s, `interp` can
 /// (and should) be None.
-pub fn transcribe(sp_diag: &Handler,
+pub fn transcribe(cx: &ExtCtxt,
                   interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
                   src: Vec<quoted::TokenTree>)
                   -> TokenStream {
@@ -120,22 +122,20 @@ pub fn transcribe(sp_diag: &Handler,
                                          &interpolations,
                                          &repeats) {
                     LockstepIterSize::Unconstrained => {
-                        panic!(sp_diag.span_fatal(
-                            sp, /* blame macro writer */
+                        cx.span_fatal(sp, /* blame macro writer */
                             "attempted to repeat an expression \
                              containing no syntax \
-                             variables matched as repeating at this depth"));
+                             variables matched as repeating at this depth");
                     }
                     LockstepIterSize::Contradiction(ref msg) => {
                         // FIXME #2887 blame macro invoker instead
-                        panic!(sp_diag.span_fatal(sp, &msg[..]));
+                        cx.span_fatal(sp, &msg[..]);
                     }
                     LockstepIterSize::Constraint(len, _) => {
                         if len == 0 {
                             if seq.op == quoted::KleeneOp::OneOrMore {
                                 // FIXME #2887 blame invoker
-                                panic!(sp_diag.span_fatal(sp,
-                                                          "this must repeat at least once"));
+                                cx.span_fatal(sp, "this must repeat at least once");
                             }
                         } else {
                             repeats.push((0, len));
@@ -149,29 +149,37 @@ pub fn transcribe(sp_diag: &Handler,
                 }
             }
             // FIXME #2887: think about span stuff here
-            quoted::TokenTree::Token(sp, SubstNt(ident)) => {
-                match lookup_cur_matched(ident, &interpolations, &repeats) {
-                    None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()),
-                    Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched {
-                        match **nt {
-                            NtTT(ref tt) => result.push(tt.clone().into()),
-                            _ => {
-                                let token = TokenTree::Token(sp, token::Interpolated(nt.clone()));
-                                result.push(token.into());
-                            }
+            quoted::TokenTree::MetaVar(mut sp, ident) => {
+                if let Some(cur_matched) = lookup_cur_matched(ident, &interpolations, &repeats) {
+                    if let MatchedNonterminal(ref nt) = *cur_matched {
+                        if let NtTT(ref tt) = **nt {
+                            result.push(tt.clone().into());
+                        } else {
+                            sp.ctxt = sp.ctxt.apply_mark(cx.current_expansion.mark);
+                            let token = TokenTree::Token(sp, Token::interpolated((**nt).clone()));
+                            result.push(token.into());
                         }
                     } else {
-                        panic!(sp_diag.span_fatal(
-                            sp, /* blame the macro writer */
-                            &format!("variable '{}' is still repeating at this depth", ident)));
+                        cx.span_fatal(sp, /* blame the macro writer */
+                            &format!("variable '{}' is still repeating at this depth", ident));
                     }
+                } else {
+                    let ident =
+                        Ident { ctxt: ident.ctxt.apply_mark(cx.current_expansion.mark), ..ident };
+                    sp.ctxt = sp.ctxt.apply_mark(cx.current_expansion.mark);
+                    result.push(TokenTree::Token(sp, token::Dollar).into());
+                    result.push(TokenTree::Token(sp, token::Ident(ident)).into());
                 }
             }
-            quoted::TokenTree::Delimited(span, delimited) => {
+            quoted::TokenTree::Delimited(mut span, delimited) => {
+                span.ctxt = span.ctxt.apply_mark(cx.current_expansion.mark);
                 stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span });
                 result_stack.push(mem::replace(&mut result, Vec::new()));
             }
-            quoted::TokenTree::Token(span, tok) => result.push(TokenTree::Token(span, tok).into()),
+            quoted::TokenTree::Token(sp, tok) => {
+                let mut marker = Marker(cx.current_expansion.mark);
+                result.push(noop_fold_tt(TokenTree::Token(sp, tok), &mut marker).into())
+            }
             quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
         }
     }
@@ -240,7 +248,7 @@ fn lockstep_iter_size(tree: &quoted::TokenTree,
                 size + lockstep_iter_size(tt, interpolations, repeats)
             })
         },
-        TokenTree::Token(_, SubstNt(name)) | TokenTree::MetaVarDecl(_, name, _) =>
+        TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) =>
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match *matched {
                     MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index df8ee189d21b3..cb625b1ac066e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -38,12 +38,19 @@ use symbol::Symbol;
 use std::ascii::AsciiExt;
 use std::env;
 
-macro_rules! setter {
+macro_rules! set {
+    (proc_macro) => {{
+        fn f(features: &mut Features, span: Span) {
+            features.declared_lib_features.push((Symbol::intern("proc_macro"), span));
+            features.proc_macro = true;
+        }
+        f as fn(&mut Features, Span)
+    }};
     ($field: ident) => {{
-        fn f(features: &mut Features) -> &mut bool {
-            &mut features.$field
+        fn f(features: &mut Features, _: Span) {
+            features.$field = true;
         }
-        f as fn(&mut Features) -> &mut bool
+        f as fn(&mut Features, Span)
     }}
 }
 
@@ -51,10 +58,9 @@ macro_rules! declare_features {
     ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
         /// Represents active features that are currently being implemented or
         /// currently being considered for addition/removal.
-        const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
-                                          Option<u32>, fn(&mut Features) -> &mut bool)] = &[
-            $((stringify!($feature), $ver, $issue, setter!($feature))),+
-        ];
+        const ACTIVE_FEATURES:
+                &'static [(&'static str, &'static str, Option<u32>, fn(&mut Features, Span))] =
+            &[$((stringify!($feature), $ver, $issue, set!($feature))),+];
 
         /// A set of features to be used by later passes.
         pub struct Features {
@@ -137,7 +143,6 @@ declare_features! (
     (active, placement_in_syntax, "1.0.0", Some(27779)),
     (active, unboxed_closures, "1.0.0", Some(29625)),
 
-    (active, allocator, "1.0.0", Some(27389)),
     (active, fundamental, "1.0.0", Some(29635)),
     (active, main, "1.0.0", Some(29634)),
     (active, needs_allocator, "1.4.0", Some(27389)),
@@ -360,6 +365,10 @@ declare_features! (
 
     // Allows unsized tuple coercion.
     (active, unsized_tuple_coercion, "1.20.0", Some(42877)),
+
+    // global allocators and their internals
+    (active, global_allocator, "1.20.0", None),
+    (active, allocator_internals, "1.20.0", None),
 );
 
 declare_features! (
@@ -379,6 +388,7 @@ declare_features! (
     // rustc internal
     (removed, unmarked_api, "1.0.0", None),
     (removed, pushpop_unsafe, "1.2.0", None),
+    (removed, allocator, "1.0.0", None),
 );
 
 declare_features! (
@@ -585,16 +595,22 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                              "the `#[rustc_on_unimplemented]` attribute \
                                               is an experimental feature",
                                              cfg_fn!(on_unimplemented))),
-    ("allocator", Whitelisted, Gated(Stability::Unstable,
-                                     "allocator",
-                                     "the `#[allocator]` attribute is an experimental feature",
-                                     cfg_fn!(allocator))),
+    ("global_allocator", Normal, Gated(Stability::Unstable,
+                                       "global_allocator",
+                                       "the `#[global_allocator]` attribute is \
+                                        an experimental feature",
+                                       cfg_fn!(global_allocator))),
+    ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
+                                            "allocator_internals",
+                                            "the `#[default_lib_allocator]` \
+                                             attribute is an experimental feature",
+                                            cfg_fn!(allocator_internals))),
     ("needs_allocator", Normal, Gated(Stability::Unstable,
-                                      "needs_allocator",
+                                      "allocator_internals",
                                       "the `#[needs_allocator]` \
                                        attribute is an experimental \
                                        feature",
-                                      cfg_fn!(needs_allocator))),
+                                      cfg_fn!(allocator_internals))),
     ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
                                          "panic_runtime",
                                          "the `#[panic_runtime]` attribute is \
@@ -1478,9 +1494,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F
                         continue
                     };
 
-                    if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
+                    if let Some(&(_, _, _, set)) = ACTIVE_FEATURES.iter()
                         .find(|& &(n, _, _, _)| name == n) {
-                        *(setter(&mut features)) = true;
+                        set(&mut features, mi.span);
                         feature_checker.collect(&features, mi.span);
                     }
                     else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
@@ -1514,7 +1530,7 @@ struct MutexFeatureChecker {
 
 impl MutexFeatureChecker {
     // If this method turns out to be a hotspot due to branching,
-    // the branching can be eliminated by modifying `setter!()` to set these spans
+    // the branching can be eliminated by modifying `set!()` to set these spans
     // only for the features that need to be checked for mutual exclusion.
     fn collect(&mut self, features: &Features, span: Span) {
         if features.proc_macro {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4c6cf49a8db43..1fc670ec9f7fb 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -22,7 +22,7 @@ use ast::*;
 use ast;
 use syntax_pos::Span;
 use codemap::{Spanned, respan};
-use parse::token;
+use parse::token::{self, Token};
 use ptr::P;
 use symbol::keywords;
 use tokenstream::*;
@@ -573,7 +573,7 @@ pub fn noop_fold_tt<T: Folder>(tt: TokenTree, fld: &mut T) -> TokenTree {
 }
 
 pub fn noop_fold_tts<T: Folder>(tts: TokenStream, fld: &mut T) -> TokenStream {
-    tts.trees().map(|tt| fld.fold_tt(tt)).collect()
+    tts.map(|tt| fld.fold_tt(tt))
 }
 
 // apply ident folder if it's an ident, apply other folds to interpolated nodes
@@ -586,9 +586,8 @@ pub fn noop_fold_token<T: Folder>(t: token::Token, fld: &mut T) -> token::Token
                 Ok(nt) => nt,
                 Err(nt) => (*nt).clone(),
             };
-            token::Interpolated(Rc::new(fld.fold_interpolated(nt)))
+            Token::interpolated(fld.fold_interpolated(nt.0))
         }
-        token::SubstNt(ident) => token::SubstNt(fld.fold_ident(ident)),
         _ => t
     }
 }
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 082930777e598..c99a09ab24e6b 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -151,7 +151,7 @@ impl<'a> Parser<'a> {
 
     pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
         let meta = match self.token {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt) => match nt.0 {
                 Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
                 _ => None,
             },
@@ -223,7 +223,7 @@ impl<'a> Parser<'a> {
     /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
         let nt_meta = match self.token {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt) => match nt.0 {
                 token::NtMeta(ref e) => Some(e.clone()),
                 _ => None,
             },
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index a35b278a4b064..09cdf26bf1fff 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -66,14 +66,15 @@ pub struct StringReader<'a> {
     token: token::Token,
     span: Span,
     open_braces: Vec<(token::DelimToken, Span)>,
-}
-
-fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
-    Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }
+    pub override_span: Option<Span>,
 }
 
 impl<'a> StringReader<'a> {
-    fn next_token(&mut self) -> TokenAndSpan {
+    fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
+        unwrap_or!(self.override_span, Span { lo: lo, hi: hi, ctxt: NO_EXPANSION})
+    }
+
+    fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
         let res = self.try_next_token();
         self.unwrap_or_abort(res)
     }
@@ -175,6 +176,7 @@ impl<'a> StringReader<'a> {
             token: token::Eof,
             span: syntax_pos::DUMMY_SP,
             open_braces: Vec::new(),
+            override_span: None,
         }
     }
 
@@ -229,12 +231,12 @@ impl<'a> StringReader<'a> {
 
     /// Report a fatal error spanning [`from_pos`, `to_pos`).
     fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
-        self.fatal_span(mk_sp(from_pos, to_pos), m)
+        self.fatal_span(self.mk_sp(from_pos, to_pos), m)
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`).
     fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
-        self.err_span(mk_sp(from_pos, to_pos), m)
+        self.err_span(self.mk_sp(from_pos, to_pos), m)
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
@@ -258,7 +260,7 @@ impl<'a> StringReader<'a> {
         for c in c.escape_default() {
             m.push(c)
         }
-        self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..])
+        self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
@@ -282,7 +284,7 @@ impl<'a> StringReader<'a> {
         for c in c.escape_default() {
             m.push(c)
         }
-        self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..])
+        self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..])
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the
@@ -306,11 +308,11 @@ impl<'a> StringReader<'a> {
             None => {
                 if self.is_eof() {
                     self.peek_tok = token::Eof;
-                    self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos);
+                    self.peek_span = self.mk_sp(self.filemap.end_pos, self.filemap.end_pos);
                 } else {
                     let start_bytepos = self.pos;
                     self.peek_tok = self.next_token_inner()?;
-                    self.peek_span = mk_sp(start_bytepos, self.pos);
+                    self.peek_span = self.mk_sp(start_bytepos, self.pos);
                 };
             }
         }
@@ -481,7 +483,7 @@ impl<'a> StringReader<'a> {
         self.with_str_from(start, |string| {
             if string == "_" {
                 self.sess.span_diagnostic
-                    .struct_span_warn(mk_sp(start, self.pos),
+                    .struct_span_warn(self.mk_sp(start, self.pos),
                                       "underscore literal suffix is not allowed")
                     .warn("this was previously accepted by the compiler but is \
                           being phased out; it will become a hard error in \
@@ -502,7 +504,7 @@ impl<'a> StringReader<'a> {
         if let Some(c) = self.ch {
             if c.is_whitespace() {
                 let msg = "called consume_any_line_comment, but there was whitespace";
-                self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg);
+                self.sess.span_diagnostic.span_err(self.mk_sp(self.pos, self.pos), msg);
             }
         }
 
@@ -545,13 +547,13 @@ impl<'a> StringReader<'a> {
 
                             Some(TokenAndSpan {
                                 tok: tok,
-                                sp: mk_sp(start_bpos, self.pos),
+                                sp: self.mk_sp(start_bpos, self.pos),
                             })
                         })
                     } else {
                         Some(TokenAndSpan {
                             tok: token::Comment,
-                            sp: mk_sp(start_bpos, self.pos),
+                            sp: self.mk_sp(start_bpos, self.pos),
                         })
                     }
                 }
@@ -584,7 +586,7 @@ impl<'a> StringReader<'a> {
                     }
                     return Some(TokenAndSpan {
                         tok: token::Shebang(self.name_from(start)),
-                        sp: mk_sp(start, self.pos),
+                        sp: self.mk_sp(start, self.pos),
                     });
                 }
             }
@@ -612,7 +614,7 @@ impl<'a> StringReader<'a> {
                 }
                 let c = Some(TokenAndSpan {
                     tok: token::Whitespace,
-                    sp: mk_sp(start_bpos, self.pos),
+                    sp: self.mk_sp(start_bpos, self.pos),
                 });
                 debug!("scanning whitespace: {:?}", c);
                 c
@@ -674,7 +676,7 @@ impl<'a> StringReader<'a> {
 
             Some(TokenAndSpan {
                 tok: tok,
-                sp: mk_sp(start_bpos, self.pos),
+                sp: self.mk_sp(start_bpos, self.pos),
             })
         })
     }
@@ -869,7 +871,7 @@ impl<'a> StringReader<'a> {
                                 let valid = if self.ch_is('{') {
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
-                                    let span = mk_sp(start, self.pos);
+                                    let span = self.mk_sp(start, self.pos);
                                     self.sess.span_diagnostic
                                         .struct_span_err(span, "incorrect unicode escape sequence")
                                         .span_help(span,
@@ -907,13 +909,13 @@ impl<'a> StringReader<'a> {
                                                                         },
                                                                         c);
                                 if e == '\r' {
-                                    err.span_help(mk_sp(escaped_pos, pos),
+                                    err.span_help(self.mk_sp(escaped_pos, pos),
                                                   "this is an isolated carriage return; consider \
                                                    checking your editor and version control \
                                                    settings");
                                 }
                                 if (e == '{' || e == '}') && !ascii_only {
-                                    err.span_help(mk_sp(escaped_pos, pos),
+                                    err.span_help(self.mk_sp(escaped_pos, pos),
                                                   "if used in a formatting string, curly braces \
                                                    are escaped with `{{` and `}}`");
                                 }
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 554a1fcfc71a6..63a396c14db85 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -19,7 +19,9 @@ impl<'a> StringReader<'a> {
     pub fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
         let mut tts = Vec::new();
         while self.token != token::Eof {
-            tts.push(self.parse_token_tree()?.into());
+            let tree = self.parse_token_tree()?;
+            let is_joint = tree.span().hi == self.span.lo && token::is_op(&self.token);
+            tts.push(if is_joint { tree.joint() } else { tree.into() });
         }
         Ok(TokenStream::concat(tts))
     }
@@ -31,13 +33,15 @@ impl<'a> StringReader<'a> {
             if let token::CloseDelim(..) = self.token {
                 return TokenStream::concat(tts);
             }
-            match self.parse_token_tree() {
-                Ok(tt) => tts.push(tt.into()),
+            let tree = match self.parse_token_tree() {
+                Ok(tree) => tree,
                 Err(mut e) => {
                     e.emit();
                     return TokenStream::concat(tts);
                 }
-            }
+            };
+            let is_joint = tree.span().hi == self.span.lo && token::is_op(&self.token);
+            tts.push(if is_joint { tree.joint() } else { tree.into() });
         }
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 3a68a6ba7646c..bd9a621c00c00 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -141,9 +141,10 @@ pub fn parse_stmt_from_source_str(name: String, source: String, sess: &ParseSess
     new_parser_from_source_str(sess, name, source).parse_stmt()
 }
 
-pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSess)
-                                        -> TokenStream {
-    filemap_to_stream(sess, sess.codemap().new_filemap(name, source))
+pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSess,
+                                    override_span: Option<Span>)
+                                    -> TokenStream {
+    filemap_to_stream(sess, sess.codemap().new_filemap(name, source), override_span)
 }
 
 // Create a new parser from a source string
@@ -177,7 +178,7 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
 /// Given a filemap and config, return a parser
 pub fn filemap_to_parser(sess: & ParseSess, filemap: Rc<FileMap>, ) -> Parser {
     let end_pos = filemap.end_pos;
-    let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap));
+    let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap, None));
 
     if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP {
         parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION };
@@ -212,8 +213,10 @@ fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
 }
 
 /// Given a filemap, produce a sequence of token-trees
-pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>) -> TokenStream {
+pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>, override_span: Option<Span>)
+                         -> TokenStream {
     let mut srdr = lexer::StringReader::new(sess, filemap);
+    srdr.override_span = override_span;
     srdr.real_token();
     panictry!(srdr.parse_all_token_trees())
 }
@@ -684,7 +687,7 @@ mod tests {
                     id: ast::DUMMY_NODE_ID,
                     node: ast::ExprKind::Path(None, ast::Path {
                         span: sp(0, 6),
-                        segments: vec![ast::PathSegment::crate_root(),
+                        segments: vec![ast::PathSegment::crate_root(sp(0, 2)),
                                        str2seg("a", 2, 3),
                                        str2seg("b", 5, 6)]
                     }),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 64506c4af4691..c248e20b608fc 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -107,7 +107,7 @@ pub enum BlockMode {
 macro_rules! maybe_whole_expr {
     ($p:expr) => {
         if let token::Interpolated(nt) = $p.token.clone() {
-            match *nt {
+            match nt.0 {
                 token::NtExpr(ref e) => {
                     $p.bump();
                     return Ok((*e).clone());
@@ -134,7 +134,7 @@ macro_rules! maybe_whole_expr {
 macro_rules! maybe_whole {
     ($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
         if let token::Interpolated(nt) = $p.token.clone() {
-            if let token::$constructor($x) = (*nt).clone() {
+            if let token::$constructor($x) = nt.0.clone() {
                 $p.bump();
                 return Ok($e);
             }
@@ -1602,7 +1602,7 @@ impl<'a> Parser<'a> {
     /// Matches token_lit = LIT_INTEGER | ...
     pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> {
         let out = match self.token {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt) => match nt.0 {
                 token::NtExpr(ref v) => match v.node {
                     ExprKind::Lit(ref lit) => { lit.node.clone() }
                     _ => { return self.unexpected_last(&self.token); }
@@ -1761,7 +1761,7 @@ impl<'a> Parser<'a> {
         };
 
         if is_global {
-            segments.insert(0, PathSegment::crate_root());
+            segments.insert(0, PathSegment::crate_root(lo));
         }
 
         // Assemble the result.
@@ -1775,7 +1775,7 @@ impl<'a> Parser<'a> {
     /// This is used when parsing derive macro paths in `#[derive]` attributes.
     pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
         let meta_ident = match self.token {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt) => match nt.0 {
                 token::NtMeta(ref meta) => match meta.node {
                     ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)),
                     _ => None,
@@ -2610,13 +2610,16 @@ impl<'a> Parser<'a> {
 
     pub fn process_potential_macro_variable(&mut self) {
         let ident = match self.token {
-            token::SubstNt(name) => {
+            token::Dollar if self.span.ctxt != syntax_pos::hygiene::SyntaxContext::empty() &&
+                             self.look_ahead(1, |t| t.is_ident()) => {
+                self.bump();
+                let name = match self.token { token::Ident(ident) => ident, _ => unreachable!() };
                 self.fatal(&format!("unknown macro variable `{}`", name)).emit();
                 return
             }
             token::Interpolated(ref nt) => {
                 self.meta_var_span = Some(self.span);
-                match **nt {
+                match nt.0 {
                     token::NtIdent(ident) => ident,
                     _ => return,
                 }
@@ -6168,7 +6171,7 @@ impl<'a> Parser<'a> {
             // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
             self.eat(&token::ModSep);
             let prefix = ast::Path {
-                segments: vec![PathSegment::crate_root()],
+                segments: vec![PathSegment::crate_root(lo)],
                 span: lo.to(self.span),
             };
             let view_path_kind = if self.eat(&token::BinOp(token::Star)) {
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 75969cf2eb85b..834ac38af9870 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -16,10 +16,12 @@ pub use self::Token::*;
 
 use ast::{self};
 use ptr::P;
+use serialize::{Decodable, Decoder, Encodable, Encoder};
 use symbol::keywords;
-use tokenstream::TokenTree;
+use tokenstream::{TokenStream, TokenTree};
 
-use std::fmt;
+use std::cell::Cell;
+use std::{cmp, fmt};
 use std::rc::Rc;
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -167,14 +169,12 @@ pub enum Token {
     Underscore,
     Lifetime(ast::Ident),
 
-    /* For interpolation */
-    Interpolated(Rc<Nonterminal>),
+    // The `LazyTokenStream` is a pure function of the `Nonterminal`,
+    // and so the `LazyTokenStream` can be ignored by Eq, Hash, etc.
+    Interpolated(Rc<(Nonterminal, LazyTokenStream)>),
     // Can be expanded into several tokens.
     /// Doc comment
     DocComment(ast::Name),
-    // In right-hand-sides of MBE macros:
-    /// A syntactic variable that will be filled in by macro expansion.
-    SubstNt(ast::Ident),
 
     // Junk. These carry no data because we don't really care about the data
     // they *would* carry, and don't really want to allocate a new ident for
@@ -190,6 +190,10 @@ pub enum Token {
 }
 
 impl Token {
+    pub fn interpolated(nt: Nonterminal) -> Token {
+        Token::Interpolated(Rc::new((nt, LazyTokenStream::new())))
+    }
+
     /// Returns `true` if the token starts with '>'.
     pub fn is_like_gt(&self) -> bool {
         match *self {
@@ -214,7 +218,7 @@ impl Token {
             Lt | BinOp(Shl)             | // associated path
             ModSep                      | // global path
             Pound                       => true, // expression attributes
-            Interpolated(ref nt) => match **nt {
+            Interpolated(ref nt) => match nt.0 {
                 NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true,
                 _ => false,
             },
@@ -237,7 +241,7 @@ impl Token {
             Lifetime(..)                | // lifetime bound in trait object
             Lt | BinOp(Shl)             | // associated path
             ModSep                      => true, // global path
-            Interpolated(ref nt) => match **nt {
+            Interpolated(ref nt) => match nt.0 {
                 NtIdent(..) | NtTy(..) | NtPath(..) => true,
                 _ => false,
             },
@@ -256,7 +260,7 @@ impl Token {
     pub fn ident(&self) -> Option<ast::Ident> {
         match *self {
             Ident(ident) => Some(ident),
-            Interpolated(ref nt) => match **nt {
+            Interpolated(ref nt) => match nt.0 {
                 NtIdent(ident) => Some(ident.node),
                 _ => None,
             },
@@ -288,7 +292,7 @@ impl Token {
     /// Returns `true` if the token is an interpolated path.
     pub fn is_path(&self) -> bool {
         if let Interpolated(ref nt) = *self {
-            if let NtPath(..) = **nt {
+            if let NtPath(..) = nt.0 {
                 return true;
             }
         }
@@ -358,6 +362,60 @@ impl Token {
         }
     }
 
+    pub fn glue(self, joint: Token) -> Option<Token> {
+        Some(match self {
+            Eq => match joint {
+                Eq => EqEq,
+                Gt => FatArrow,
+                _ => return None,
+            },
+            Lt => match joint {
+                Eq => Le,
+                Lt => BinOp(Shl),
+                Le => BinOpEq(Shl),
+                BinOp(Minus) => LArrow,
+                _ => return None,
+            },
+            Gt => match joint {
+                Eq => Ge,
+                Gt => BinOp(Shr),
+                Ge => BinOpEq(Shr),
+                _ => return None,
+            },
+            Not => match joint {
+                Eq => Ne,
+                _ => return None,
+            },
+            BinOp(op) => match joint {
+                Eq => BinOpEq(op),
+                BinOp(And) if op == And => AndAnd,
+                BinOp(Or) if op == Or => OrOr,
+                Gt if op == Minus => RArrow,
+                _ => return None,
+            },
+            Dot => match joint {
+                Dot => DotDot,
+                DotDot => DotDotDot,
+                _ => return None,
+            },
+            DotDot => match joint {
+                Dot => DotDotDot,
+                _ => return None,
+            },
+            Colon => match joint {
+                Colon => ModSep,
+                _ => return None,
+            },
+
+            Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | Comma |
+            Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question |
+            OpenDelim(..) | CloseDelim(..) | Underscore => return None,
+
+            Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
+            Whitespace | Comment | Shebang(..) | Eof => return None,
+        })
+    }
+
     /// Returns `true` if the token is either a special identifier or a keyword.
     pub fn is_reserved_ident(&self) -> bool {
         self.is_special_ident() || self.is_used_keyword() || self.is_unused_keyword()
@@ -411,3 +469,66 @@ impl fmt::Debug for Nonterminal {
         }
     }
 }
+
+pub fn is_op(tok: &Token) -> bool {
+    match *tok {
+        OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) |
+        Ident(..) | Underscore | Lifetime(..) | Interpolated(..) |
+        Whitespace | Comment | Shebang(..) | Eof => false,
+        _ => true,
+    }
+}
+
+pub struct LazyTokenStream(Cell<Option<TokenStream>>);
+
+impl Clone for LazyTokenStream {
+    fn clone(&self) -> Self {
+        let opt_stream = self.0.take();
+        self.0.set(opt_stream.clone());
+        LazyTokenStream(Cell::new(opt_stream))
+    }
+}
+
+impl cmp::Eq for LazyTokenStream {}
+impl PartialEq for LazyTokenStream {
+    fn eq(&self, _other: &LazyTokenStream) -> bool {
+        true
+    }
+}
+
+impl fmt::Debug for LazyTokenStream {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.clone().0.into_inner(), f)
+    }
+}
+
+impl LazyTokenStream {
+    pub fn new() -> Self {
+        LazyTokenStream(Cell::new(None))
+    }
+
+    pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream {
+        let mut opt_stream = self.0.take();
+        if opt_stream.is_none() {
+            opt_stream = Some(f());
+        }
+        self.0.set(opt_stream.clone());
+        opt_stream.clone().unwrap()
+    }
+}
+
+impl Encodable for LazyTokenStream {
+    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
+        Ok(())
+    }
+}
+
+impl Decodable for LazyTokenStream {
+    fn decode<D: Decoder>(_: &mut D) -> Result<LazyTokenStream, D::Error> {
+        Ok(LazyTokenStream::new())
+    }
+}
+
+impl ::std::hash::Hash for LazyTokenStream {
+    fn hash<H: ::std::hash::Hasher>(&self, _hasher: &mut H) {}
+}
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6c00e0b9efd7e..d449e412d6cc3 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -270,13 +270,12 @@ pub fn token_to_string(tok: &Token) -> String {
 
         /* Other */
         token::DocComment(s)        => s.to_string(),
-        token::SubstNt(s)           => format!("${}", s),
         token::Eof                  => "<eof>".to_string(),
         token::Whitespace           => " ".to_string(),
         token::Comment              => "/* */".to_string(),
         token::Shebang(s)           => format!("/* shebang: {}*/", s),
 
-        token::Interpolated(ref nt) => match **nt {
+        token::Interpolated(ref nt) => match nt.0 {
             token::NtExpr(ref e)        => expr_to_string(e),
             token::NtMeta(ref e)        => meta_item_to_string(e),
             token::NtTy(ref e)          => ty_to_string(e),
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 963482fc223f1..8eee25405df6b 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -138,6 +138,10 @@ impl TokenTree {
             _ => false,
         }
     }
+
+    pub fn joint(self) -> TokenStream {
+        TokenStream { kind: TokenStreamKind::JointTree(self) }
+    }
 }
 
 /// # Token Streams
@@ -155,6 +159,7 @@ pub struct TokenStream {
 enum TokenStreamKind {
     Empty,
     Tree(TokenTree),
+    JointTree(TokenTree),
     Stream(RcSlice<TokenStream>),
 }
 
@@ -199,7 +204,7 @@ impl TokenStream {
     pub fn concat(mut streams: Vec<TokenStream>) -> TokenStream {
         match streams.len() {
             0 => TokenStream::empty(),
-            1 => TokenStream::from(streams.pop().unwrap()),
+            1 => streams.pop().unwrap(),
             _ => TokenStream::concat_rc_slice(RcSlice::new(streams)),
         }
     }
@@ -225,6 +230,105 @@ impl TokenStream {
         }
         true
     }
+
+    /// Precondition: `self` consists of a single token tree.
+    /// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`.
+    pub fn as_tree(self) -> (TokenTree, bool /* joint? */) {
+        match self.kind {
+            TokenStreamKind::Tree(tree) => (tree, false),
+            TokenStreamKind::JointTree(tree) => (tree, true),
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
+        let mut trees = self.into_trees();
+        let mut result = Vec::new();
+        while let Some(stream) = trees.next_as_stream() {
+            result.push(match stream.kind {
+                TokenStreamKind::Tree(tree) => f(tree).into(),
+                TokenStreamKind::JointTree(tree) => f(tree).joint(),
+                _ => unreachable!()
+            });
+        }
+        TokenStream::concat(result)
+    }
+
+    fn first_tree(&self) -> Option<TokenTree> {
+        match self.kind {
+            TokenStreamKind::Empty => None,
+            TokenStreamKind::Tree(ref tree) |
+            TokenStreamKind::JointTree(ref tree) => Some(tree.clone()),
+            TokenStreamKind::Stream(ref stream) => stream.first().unwrap().first_tree(),
+        }
+    }
+
+    fn last_tree_if_joint(&self) -> Option<TokenTree> {
+        match self.kind {
+            TokenStreamKind::Empty | TokenStreamKind::Tree(..) => None,
+            TokenStreamKind::JointTree(ref tree) => Some(tree.clone()),
+            TokenStreamKind::Stream(ref stream) => stream.last().unwrap().last_tree_if_joint(),
+        }
+    }
+}
+
+pub struct TokenStreamBuilder(Vec<TokenStream>);
+
+impl TokenStreamBuilder {
+    pub fn new() -> TokenStreamBuilder {
+        TokenStreamBuilder(Vec::new())
+    }
+
+    pub fn push<T: Into<TokenStream>>(&mut self, stream: T) {
+        let stream = stream.into();
+        let last_tree_if_joint = self.0.last().and_then(TokenStream::last_tree_if_joint);
+        if let Some(TokenTree::Token(last_span, last_tok)) = last_tree_if_joint {
+            if let Some(TokenTree::Token(span, tok)) = stream.first_tree() {
+                if let Some(glued_tok) = last_tok.glue(tok) {
+                    let last_stream = self.0.pop().unwrap();
+                    self.push_all_but_last_tree(&last_stream);
+                    let glued_span = last_span.to(span);
+                    self.0.push(TokenTree::Token(glued_span, glued_tok).into());
+                    self.push_all_but_first_tree(&stream);
+                    return
+                }
+            }
+        }
+        self.0.push(stream);
+    }
+
+    pub fn add<T: Into<TokenStream>>(mut self, stream: T) -> Self {
+        self.push(stream);
+        self
+    }
+
+    pub fn build(self) -> TokenStream {
+        TokenStream::concat(self.0)
+    }
+
+    fn push_all_but_last_tree(&mut self, stream: &TokenStream) {
+        if let TokenStreamKind::Stream(ref streams) = stream.kind {
+            let len = streams.len();
+            match len {
+                1 => {}
+                2 => self.0.push(streams[0].clone().into()),
+                _ => self.0.push(TokenStream::concat_rc_slice(streams.sub_slice(0 .. len - 1))),
+            }
+            self.push_all_but_last_tree(&streams[len - 1])
+        }
+    }
+
+    fn push_all_but_first_tree(&mut self, stream: &TokenStream) {
+        if let TokenStreamKind::Stream(ref streams) = stream.kind {
+            let len = streams.len();
+            match len {
+                1 => {}
+                2 => self.0.push(streams[1].clone().into()),
+                _ => self.0.push(TokenStream::concat_rc_slice(streams.sub_slice(1 .. len))),
+            }
+            self.push_all_but_first_tree(&streams[0])
+        }
+    }
 }
 
 #[derive(Clone)]
@@ -234,6 +338,7 @@ pub struct Cursor(CursorKind);
 enum CursorKind {
     Empty,
     Tree(TokenTree, bool /* consumed? */),
+    JointTree(TokenTree, bool /* consumed? */),
     Stream(StreamCursor),
 }
 
@@ -244,42 +349,45 @@ struct StreamCursor {
     stack: Vec<(RcSlice<TokenStream>, usize)>,
 }
 
-impl Iterator for Cursor {
-    type Item = TokenTree;
-
-    fn next(&mut self) -> Option<TokenTree> {
-        let cursor = match self.0 {
-            CursorKind::Stream(ref mut cursor) => cursor,
-            CursorKind::Tree(ref tree, ref mut consumed @ false) => {
-                *consumed = true;
-                return Some(tree.clone());
-            }
-            _ => return None,
-        };
+impl StreamCursor {
+    fn new(stream: RcSlice<TokenStream>) -> Self {
+        StreamCursor { stream: stream, index: 0, stack: Vec::new() }
+    }
 
+    fn next_as_stream(&mut self) -> Option<TokenStream> {
         loop {
-            if cursor.index < cursor.stream.len() {
-                match cursor.stream[cursor.index].kind.clone() {
-                    TokenStreamKind::Tree(tree) => {
-                        cursor.index += 1;
-                        return Some(tree);
-                    }
-                    TokenStreamKind::Stream(stream) => {
-                        cursor.stack.push((mem::replace(&mut cursor.stream, stream),
-                                           mem::replace(&mut cursor.index, 0) + 1));
-                    }
-                    TokenStreamKind::Empty => {
-                        cursor.index += 1;
-                    }
+            if self.index < self.stream.len() {
+                self.index += 1;
+                let next = self.stream[self.index - 1].clone();
+                match next.kind {
+                    TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => return Some(next),
+                    TokenStreamKind::Stream(stream) => self.insert(stream),
+                    TokenStreamKind::Empty => {}
                 }
-            } else if let Some((stream, index)) = cursor.stack.pop() {
-                cursor.stream = stream;
-                cursor.index = index;
+            } else if let Some((stream, index)) = self.stack.pop() {
+                self.stream = stream;
+                self.index = index;
             } else {
                 return None;
             }
         }
     }
+
+    fn insert(&mut self, stream: RcSlice<TokenStream>) {
+        self.stack.push((mem::replace(&mut self.stream, stream),
+                         mem::replace(&mut self.index, 0)));
+    }
+}
+
+impl Iterator for Cursor {
+    type Item = TokenTree;
+
+    fn next(&mut self) -> Option<TokenTree> {
+        self.next_as_stream().map(|stream| match stream.kind {
+            TokenStreamKind::Tree(tree) | TokenStreamKind::JointTree(tree) => tree,
+            _ => unreachable!()
+        })
+    }
 }
 
 impl Cursor {
@@ -287,18 +395,49 @@ impl Cursor {
         Cursor(match stream.kind {
             TokenStreamKind::Empty => CursorKind::Empty,
             TokenStreamKind::Tree(tree) => CursorKind::Tree(tree, false),
-            TokenStreamKind::Stream(stream) => {
-                CursorKind::Stream(StreamCursor { stream: stream, index: 0, stack: Vec::new() })
-            }
+            TokenStreamKind::JointTree(tree) => CursorKind::JointTree(tree, false),
+            TokenStreamKind::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)),
         })
     }
 
-    pub fn original_stream(self) -> TokenStream {
+    pub fn next_as_stream(&mut self) -> Option<TokenStream> {
+        let (stream, consumed) = match self.0 {
+            CursorKind::Tree(ref tree, ref mut consumed @ false) =>
+                (tree.clone().into(), consumed),
+            CursorKind::JointTree(ref tree, ref mut consumed @ false) =>
+                (tree.clone().joint(), consumed),
+            CursorKind::Stream(ref mut cursor) => return cursor.next_as_stream(),
+            _ => return None,
+        };
+
+        *consumed = true;
+        Some(stream)
+    }
+
+    pub fn insert(&mut self, stream: TokenStream) {
+        match self.0 {
+            _ if stream.is_empty() => return,
+            CursorKind::Empty => *self = stream.trees(),
+            CursorKind::Tree(_, consumed) | CursorKind::JointTree(_, consumed) => {
+                *self = TokenStream::concat(vec![self.original_stream(), stream]).trees();
+                if consumed {
+                    self.next();
+                }
+            }
+            CursorKind::Stream(ref mut cursor) => {
+                cursor.insert(ThinTokenStream::from(stream).0.unwrap());
+            }
+        }
+    }
+
+    pub fn original_stream(&self) -> TokenStream {
         match self.0 {
             CursorKind::Empty => TokenStream::empty(),
-            CursorKind::Tree(tree, _) => tree.into(),
-            CursorKind::Stream(cursor) => TokenStream::concat_rc_slice({
-                cursor.stack.get(0).cloned().map(|(stream, _)| stream).unwrap_or(cursor.stream)
+            CursorKind::Tree(ref tree, _) => tree.clone().into(),
+            CursorKind::JointTree(ref tree, _) => tree.clone().joint(),
+            CursorKind::Stream(ref cursor) => TokenStream::concat_rc_slice({
+                cursor.stack.get(0).cloned().map(|(stream, _)| stream)
+                    .unwrap_or(cursor.stream.clone())
             }),
         }
     }
@@ -307,8 +446,9 @@ impl Cursor {
         fn look_ahead(streams: &[TokenStream], mut n: usize) -> Result<TokenTree, usize> {
             for stream in streams {
                 n = match stream.kind {
-                    TokenStreamKind::Tree(ref tree) if n == 0 => return Ok(tree.clone()),
-                    TokenStreamKind::Tree(..) => n - 1,
+                    TokenStreamKind::Tree(ref tree) | TokenStreamKind::JointTree(ref tree)
+                        if n == 0 => return Ok(tree.clone()),
+                    TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => n - 1,
                     TokenStreamKind::Stream(ref stream) => match look_ahead(stream, n) {
                         Ok(tree) => return Ok(tree),
                         Err(n) => n,
@@ -316,13 +456,15 @@ impl Cursor {
                     _ => n,
                 };
             }
-
             Err(n)
         }
 
         match self.0 {
-            CursorKind::Empty | CursorKind::Tree(_, true) => Err(n),
-            CursorKind::Tree(ref tree, false) => look_ahead(&[tree.clone().into()], n),
+            CursorKind::Empty |
+            CursorKind::Tree(_, true) |
+            CursorKind::JointTree(_, true) => Err(n),
+            CursorKind::Tree(ref tree, false) |
+            CursorKind::JointTree(ref tree, false) => look_ahead(&[tree.clone().into()], n),
             CursorKind::Stream(ref cursor) => {
                 look_ahead(&cursor.stream[cursor.index ..], n).or_else(|mut n| {
                     for &(ref stream, index) in cursor.stack.iter().rev() {
@@ -350,6 +492,7 @@ impl From<TokenStream> for ThinTokenStream {
         ThinTokenStream(match stream.kind {
             TokenStreamKind::Empty => None,
             TokenStreamKind::Tree(tree) => Some(RcSlice::new(vec![tree.into()])),
+            TokenStreamKind::JointTree(tree) => Some(RcSlice::new(vec![tree.joint()])),
             TokenStreamKind::Stream(stream) => Some(stream),
         })
     }
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index 2727ab79ebf76..d993ba14a4ab5 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -20,7 +20,7 @@ use std::iter::Peekable;
 /// Map a string to tts, using a made-up filename:
 pub fn string_to_stream(source_str: String) -> TokenStream {
     let ps = ParseSess::new(FilePathMapping::empty());
-    filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str))
+    filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str), None)
 }
 
 /// Map string to parser (via tts)
diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs
index 2d9fd7aa87553..d6939d71129e4 100644
--- a/src/libsyntax/util/rc_slice.rs
+++ b/src/libsyntax/util/rc_slice.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use std::fmt;
-use std::ops::Deref;
+use std::ops::{Deref, Range};
 use std::rc::Rc;
 
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
@@ -30,6 +30,14 @@ impl<T> RcSlice<T> {
             data: Rc::new(vec.into_boxed_slice()),
         }
     }
+
+    pub fn sub_slice(&self, range: Range<usize>) -> Self {
+        RcSlice {
+            data: self.data.clone(),
+            offset: self.offset + range.start as u32,
+            len: (range.end - range.start) as u32,
+        }
+    }
 }
 
 impl<T> Deref for RcSlice<T> {
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index dc4b8eb24cd0a..6f4c112acb6c6 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -15,6 +15,8 @@ use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax_pos::Span;
+use syntax_pos::symbol::Symbol;
+use syntax_pos::hygiene::SyntaxContext;
 use syntax::tokenstream::TokenTree;
 
 pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt,
@@ -50,7 +52,10 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt,
             }
         }
     }
-    let res = ast::Ident::from_str(&res_str);
+    let res = ast::Ident {
+        name: Symbol::intern(&res_str),
+        ctxt: SyntaxContext::empty().apply_mark(cx.current_expansion.mark),
+    };
 
     struct Result {
         ident: ast::Ident,
diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs
index b01ef65e5fe5e..fa5537b5d8fe3 100644
--- a/src/libsyntax_ext/deriving/custom.rs
+++ b/src/libsyntax_ext/deriving/custom.rs
@@ -16,7 +16,6 @@ use syntax::ast::{self, ItemKind, Attribute, Mac};
 use syntax::attr::{mark_used, mark_known};
 use syntax::codemap::Span;
 use syntax::ext::base::*;
-use syntax::fold::Folder;
 use syntax::visit::Visitor;
 
 struct MarkAttrs<'a>(&'a [ast::Name]);
@@ -75,7 +74,7 @@ impl MultiItemModifier for ProcMacroDerive {
         MarkAttrs(&self.attrs).visit_item(&item);
 
         let input = __internal::new_token_stream(ecx.resolver.eliminate_crate_var(item.clone()));
-        let res = __internal::set_parse_sess(&ecx.parse_sess, || {
+        let res = __internal::set_sess(ecx, || {
             let inner = self.inner;
             panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
         });
@@ -97,9 +96,9 @@ impl MultiItemModifier for ProcMacroDerive {
             }
         };
 
-        let new_items = __internal::set_parse_sess(&ecx.parse_sess, || {
+        __internal::set_sess(ecx, || {
             match __internal::token_stream_parse_items(stream) {
-                Ok(new_items) => new_items,
+                Ok(new_items) => new_items.into_iter().map(Annotatable::Item).collect(),
                 Err(_) => {
                     // FIXME: handle this better
                     let msg = "proc-macro derive produced unparseable tokens";
@@ -107,12 +106,6 @@ impl MultiItemModifier for ProcMacroDerive {
                     panic!(FatalError);
                 }
             }
-        });
-
-        // Reassign spans of all expanded items to the input `item`
-        // for better errors here.
-        new_items.into_iter().map(|item| {
-            Annotatable::Item(ChangeSpan { span: span }.fold_item(item).expect_one(""))
-        }).collect()
+        })
     }
 }
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index a6768c07fe13b..144d1930df90b 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -20,7 +20,7 @@ use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
 use syntax::tokenstream;
 
 use std::collections::{HashMap, HashSet};
@@ -558,7 +558,9 @@ impl<'a, 'b> Context<'a, 'b> {
         // passed to this function.
         for (i, e) in self.args.into_iter().enumerate() {
             let name = self.ecx.ident_of(&format!("__arg{}", i));
-            pats.push(self.ecx.pat_ident(DUMMY_SP, name));
+            let span =
+                Span { ctxt: e.span.ctxt.apply_mark(self.ecx.current_expansion.mark), ..e.span };
+            pats.push(self.ecx.pat_ident(span, name));
             for ref arg_ty in self.arg_unique_types[i].iter() {
                 locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
             }
@@ -672,10 +674,10 @@ impl<'a, 'b> Context<'a, 'b> {
 }
 
 pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt,
-                               sp: Span,
+                               mut sp: Span,
                                tts: &[tokenstream::TokenTree])
                                -> Box<base::MacResult + 'cx> {
-
+    sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark);
     match parse_args(ecx, sp, tts) {
         Some((efmt, args, names)) => {
             MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names))
@@ -696,7 +698,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
     // `ArgumentType` does not derive `Clone`.
     let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
     let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
-    let macsp = ecx.call_site();
+    let mut macsp = ecx.call_site();
+    macsp.ctxt = macsp.ctxt.apply_mark(ecx.current_expansion.mark);
     let msg = "format argument must be a string literal.";
     let fmt = match expr_to_spanned_string(ecx, efmt, msg) {
         Some(fmt) => fmt,
diff --git a/src/libsyntax_ext/proc_macro_impl.rs b/src/libsyntax_ext/proc_macro_impl.rs
index f60e5824db962..5fcedbf50c60f 100644
--- a/src/libsyntax_ext/proc_macro_impl.rs
+++ b/src/libsyntax_ext/proc_macro_impl.rs
@@ -34,7 +34,7 @@ impl base::AttrProcMacro for AttrProcMacro {
         let annotation = __internal::token_stream_wrap(annotation);
         let annotated = __internal::token_stream_wrap(annotated);
 
-        let res = __internal::set_parse_sess(&ecx.parse_sess, || {
+        let res = __internal::set_sess(ecx, || {
             panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(annotation, annotated)))
         });
 
@@ -69,7 +69,7 @@ impl base::ProcMacro for BangProcMacro {
                    -> TokenStream {
         let input = __internal::token_stream_wrap(input);
 
-        let res = __internal::set_parse_sess(&ecx.parse_sess, || {
+        let res = __internal::set_sess(ecx, || {
             panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(input)))
         });
 
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index f2ccc3f051e92..804b91ab09e3c 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -144,24 +144,18 @@ impl SyntaxContext {
     pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
         HygieneData::with(|data| {
             let syntax_contexts = &mut data.syntax_contexts;
-            let ctxt_data = syntax_contexts[self.0 as usize];
-            if mark == ctxt_data.outer_mark {
-                return ctxt_data.prev_ctxt;
-            }
-
-            let modern = if data.marks[mark.0 as usize].modern {
-                *data.markings.entry((ctxt_data.modern, mark)).or_insert_with(|| {
-                    let modern = SyntaxContext(syntax_contexts.len() as u32);
+            let mut modern = syntax_contexts[self.0 as usize].modern;
+            if data.marks[mark.0 as usize].modern {
+                modern = *data.markings.entry((modern, mark)).or_insert_with(|| {
+                    let len = syntax_contexts.len() as u32;
                     syntax_contexts.push(SyntaxContextData {
                         outer_mark: mark,
-                        prev_ctxt: ctxt_data.modern,
-                        modern: modern,
+                        prev_ctxt: modern,
+                        modern: SyntaxContext(len),
                     });
-                    modern
-                })
-            } else {
-                ctxt_data.modern
-            };
+                    SyntaxContext(len)
+                });
+            }
 
             *data.markings.entry((self, mark)).or_insert_with(|| {
                 syntax_contexts.push(SyntaxContextData {
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index bb62efd376a0b..a7c247689cce8 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -186,7 +186,7 @@ impl Span {
 
     pub fn to(self, end: Span) -> Span {
         // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
-        if end.ctxt == SyntaxContext::empty() {
+        if self.ctxt == SyntaxContext::empty() {
             Span { lo: self.lo, ..end }
         } else {
             Span { hi: end.hi, ..self }
diff --git a/src/rustc/compiler_builtins_shim/Cargo.toml b/src/rustc/compiler_builtins_shim/Cargo.toml
new file mode 100644
index 0000000000000..e0026078a5d72
--- /dev/null
+++ b/src/rustc/compiler_builtins_shim/Cargo.toml
@@ -0,0 +1,24 @@
+# See libc_shim/Cargo.toml for why this exists
+
+[package]
+name = "compiler_builtins"
+authors = ["The Rust Project Developers"]
+version = "0.0.0"
+build = "../../libcompiler_builtins/build.rs"
+
+[lib]
+path = "../../libcompiler_builtins/src/lib.rs"
+test = false
+doctest = false
+
+[dependencies]
+core = { path = "../../libcore" }
+
+[build-dependencies]
+gcc = "0.3"
+
+[features]
+c = []
+default = ["c", "rustbuild", "compiler-builtins"]
+rustbuild = []
+compiler-builtins = []
diff --git a/src/test/run-pass/allocator-system.rs b/src/rustc/compiler_builtins_shim/build.rs
similarity index 75%
rename from src/test/run-pass/allocator-system.rs
rename to src/rustc/compiler_builtins_shim/build.rs
index 4585003d5793b..546f60482e7bc 100644
--- a/src/test/run-pass/allocator-system.rs
+++ b/src/rustc/compiler_builtins_shim/build.rs
@@ -8,12 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// no-prefer-dynamic
+#![deny(warnings)]
 
-#![feature(alloc_system)]
-
-extern crate alloc_system;
+// See comments in Cargo.toml for why this exists
 
 fn main() {
-    println!("{:?}", Box::new(3));
+    println!("cargo:rustc-cfg=stdbuild");
+    println!("cargo:rerun-if-changed=build.rs");
 }
diff --git a/src/rustllvm/.editorconfig b/src/rustllvm/.editorconfig
new file mode 100644
index 0000000000000..865cd45f708fb
--- /dev/null
+++ b/src/rustllvm/.editorconfig
@@ -0,0 +1,6 @@
+[*.{h,cpp}]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_style = space
+indent_size = 2
diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger
index 37ba326445265..b2d4c11329512 100644
--- a/src/rustllvm/llvm-rebuild-trigger
+++ b/src/rustllvm/llvm-rebuild-trigger
@@ -1,4 +1,8 @@
 # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
+<<<<<<< 37849a002ed91ac2b80aeb2172364b4e19250e05
 2017-06-27
+=======
+2017-06-26
+>>>>>>> rustc: Implement the #[global_allocator] attribute
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index bc84ac49da985..d8bbcd9b7328e 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -11,7 +11,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(allocator)]
+#![feature(custom_attribute)]
 
 pub struct S {
   _field: [i64; 4],
diff --git a/src/test/compile-fail/allocator-depends-on-needs-allocators.rs b/src/test/compile-fail/allocator-depends-on-needs-allocators.rs
deleted file mode 100644
index 7f420ff735a3e..0000000000000
--- a/src/test/compile-fail/allocator-depends-on-needs-allocators.rs
+++ /dev/null
@@ -1,21 +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.
-
-// error-pattern: `allocator3` cannot depend on a crate that needs an allocator
-// aux-build:needs_allocator.rs
-// aux-build:allocator3.rs
-
-// The needs_allocator crate is a dependency of the allocator crate allocator3,
-// which is not allowed
-
-extern crate allocator3;
-
-fn main() {
-}
diff --git a/src/test/compile-fail/allocator-dylib-is-system.rs b/src/test/compile-fail/allocator-dylib-is-system.rs
deleted file mode 100644
index 31009554c690d..0000000000000
--- a/src/test/compile-fail/allocator-dylib-is-system.rs
+++ /dev/null
@@ -1,41 +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.
-
-// ignore-musl no dylibs
-// aux-build:allocator-dylib.rs
-// aux-build:allocator1.rs
-// no-prefer-dynamic
-// error-pattern: cannot link together two allocators
-
-// Verify that the allocator for statically linked dynamic libraries is the
-// system allocator. Do this by linking in jemalloc and making sure that we get
-// an error.
-
-// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
-
-#![feature(alloc_jemalloc)]
-
-extern crate allocator_dylib;
-
-// The main purpose of this test is to ensure that `alloc_jemalloc` **fails**
-// here (specifically the jemalloc allocator), but currently jemalloc is
-// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure
-// that this just passes on those platforms we link in some other allocator to
-// ensure we get the same error.
-//
-// So long as we CI linux/macOS we should be good.
-#[cfg(any(target_os = "linux", target_os = "macos"))]
-extern crate alloc_jemalloc;
-#[cfg(not(any(target_os = "linux", target_os = "macos")))]
-extern crate allocator1;
-
-fn main() {
-    allocator_dylib::foo();
-}
diff --git a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
deleted file mode 100644
index 68e01bad96bb2..0000000000000
--- a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
+++ /dev/null
@@ -1,41 +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.
-
-// ignore-musl no dylibs
-// aux-build:allocator-dylib2.rs
-// aux-build:allocator1.rs
-// error-pattern: cannot link together two allocators
-
-// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
-// by linking in the system allocator here and ensuring that we get a complaint.
-
-// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
-
-#![feature(alloc_system)]
-
-extern crate allocator_dylib2;
-
-// The main purpose of this test is to ensure that `alloc_system` **fails**
-// here (specifically the system allocator), but currently system is
-// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure
-// that this just passes on those platforms we link in some other allocator to
-// ensure we get the same error.
-//
-// So long as we CI linux/macOS we should be good.
-#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-          target_os = "macos"))]
-extern crate alloc_system;
-#[cfg(not(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-              target_os = "macos")))]
-extern crate allocator1;
-
-fn main() {
-    allocator_dylib2::foo();
-}
diff --git a/src/test/compile-fail/auxiliary/allocator3.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs
similarity index 71%
rename from src/test/compile-fail/auxiliary/allocator3.rs
rename to src/test/compile-fail/allocator/auxiliary/system-allocator.rs
index d3eb1f6f7abac..4761dc421d7f7 100644
--- a/src/test/compile-fail/auxiliary/allocator3.rs
+++ b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -10,10 +10,10 @@
 
 // no-prefer-dynamic
 
-#![feature(allocator)]
-#![no_std]
-#![allocator]
+#![feature(global_allocator, allocator_api)]
 #![crate_type = "rlib"]
 
-extern crate needs_allocator;
+use std::heap::System;
 
+#[global_allocator]
+static A: System = System;
diff --git a/src/test/compile-fail/auxiliary/needs_allocator.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
similarity index 71%
rename from src/test/compile-fail/auxiliary/needs_allocator.rs
rename to src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
index 5100316042732..4761dc421d7f7 100644
--- a/src/test/compile-fail/auxiliary/needs_allocator.rs
+++ b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -10,7 +10,10 @@
 
 // no-prefer-dynamic
 
-#![feature(needs_allocator)]
-#![no_std]
-#![needs_allocator]
+#![feature(global_allocator, allocator_api)]
 #![crate_type = "rlib"]
+
+use std::heap::System;
+
+#[global_allocator]
+static A: System = System;
diff --git a/src/test/compile-fail/allocator/function-allocator.rs b/src/test/compile-fail/allocator/function-allocator.rs
new file mode 100644
index 0000000000000..50f82607b53f6
--- /dev/null
+++ b/src/test/compile-fail/allocator/function-allocator.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![feature(global_allocator)]
+
+#[global_allocator]
+fn foo() {} //~ ERROR: allocators must be statics
+
+fn main() {}
diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs
new file mode 100644
index 0000000000000..e430143506346
--- /dev/null
+++ b/src/test/compile-fail/allocator/not-an-allocator.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(global_allocator, heap_api)]
+
+#[global_allocator]
+static A: usize = 0;
+//~^ the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+
+fn main() {}
diff --git a/src/test/compile-fail/two-allocators.rs b/src/test/compile-fail/allocator/two-allocators.rs
similarity index 59%
rename from src/test/compile-fail/two-allocators.rs
rename to src/test/compile-fail/allocator/two-allocators.rs
index a34f77de2455b..b46ba6334a2b4 100644
--- a/src/test/compile-fail/two-allocators.rs
+++ b/src/test/compile-fail/allocator/two-allocators.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,12 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: cannot link together two allocators
+#![feature(global_allocator, allocator_api)]
 
-// aux-build:allocator1.rs
-// aux-build:allocator2.rs
+use std::heap::System;
 
-extern crate allocator1;
-extern crate allocator2;
+#[global_allocator]
+static A: System = System;
+#[global_allocator]
+static B: System = System;
+//~^ ERROR: cannot define more than one #[global_allocator]
 
 fn main() {}
+
diff --git a/src/test/compile-fail/allocator/two-allocators2.rs b/src/test/compile-fail/allocator/two-allocators2.rs
new file mode 100644
index 0000000000000..e342c1f9c44e7
--- /dev/null
+++ b/src/test/compile-fail/allocator/two-allocators2.rs
@@ -0,0 +1,25 @@
+// 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.
+
+// aux-build:system-allocator.rs
+// no-prefer-dynamic
+// error-pattern: the #[global_allocator] in
+
+#![feature(global_allocator, allocator_api)]
+
+extern crate system_allocator;
+
+use std::heap::System;
+
+#[global_allocator]
+static A: System = System;
+
+fn main() {}
+
diff --git a/src/test/compile-fail/allocator/two-allocators3.rs b/src/test/compile-fail/allocator/two-allocators3.rs
new file mode 100644
index 0000000000000..c310d94f6dfd8
--- /dev/null
+++ b/src/test/compile-fail/allocator/two-allocators3.rs
@@ -0,0 +1,21 @@
+// 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.
+
+// aux-build:system-allocator.rs
+// aux-build:system-allocator2.rs
+// no-prefer-dynamic
+// error-pattern: the #[global_allocator] in
+
+#![feature(global_allocator)]
+
+extern crate system_allocator;
+extern crate system_allocator2;
+
+fn main() {}
diff --git a/src/test/compile-fail/asm-out-assign-imm.rs b/src/test/compile-fail/asm-out-assign-imm.rs
index 3c4a5dcb7b038..f95e4410381d9 100644
--- a/src/test/compile-fail/asm-out-assign-imm.rs
+++ b/src/test/compile-fail/asm-out-assign-imm.rs
@@ -28,7 +28,6 @@ pub fn main() {
         asm!("mov $1, $0" : "=r"(x) : "r"(5));
         //~^ ERROR re-assignment of immutable variable `x`
         //~| NOTE re-assignment of immutable
-        //~| NOTE in this expansion of asm!
     }
     foo(x);
 }
diff --git a/src/test/run-pass/auxiliary/clibrary.rs b/src/test/compile-fail/feature-gate-allocator_internals.rs
similarity index 81%
rename from src/test/run-pass/auxiliary/clibrary.rs
rename to src/test/compile-fail/feature-gate-allocator_internals.rs
index 7438ba21bfc4a..b519a985ec5e7 100644
--- a/src/test/run-pass/auxiliary/clibrary.rs
+++ b/src/test/compile-fail/feature-gate-allocator_internals.rs
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// no-prefer-dynamic
-#![crate_type = "staticlib"]
+#![default_lib_allocator] //~ ERROR: attribute is an experimental feature
+
+fn main() {}
 
-#[no_mangle]
-pub extern "C" fn foo(x:i32) -> i32 { x }
diff --git a/src/test/compile-fail/auxiliary/allocator-dylib.rs b/src/test/compile-fail/feature-gate-global_allocator.rs
similarity index 70%
rename from src/test/compile-fail/auxiliary/allocator-dylib.rs
rename to src/test/compile-fail/feature-gate-global_allocator.rs
index 568b247ecdbf3..ff3c342f9e003 100644
--- a/src/test/compile-fail/auxiliary/allocator-dylib.rs
+++ b/src/test/compile-fail/feature-gate-global_allocator.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// no-prefer-dynamic
+#[global_allocator] //~ ERROR: attribute is an experimental feature
+static A: usize = 0;
 
-#![crate_type = "dylib"]
-
-pub fn foo() {}
+fn main() {}
diff --git a/src/test/compile-fail/macro-context.rs b/src/test/compile-fail/macro-context.rs
index 80802e19f8401..cc714a6e43141 100644
--- a/src/test/compile-fail/macro-context.rs
+++ b/src/test/compile-fail/macro-context.rs
@@ -23,5 +23,5 @@ fn main() {
         m!() => {}  //~ NOTE the usage of `m!` is likely invalid in pattern context
     }
 
-    m!();
+    m!(); //~ NOTE in this expansion
 }
diff --git a/src/test/compile-fail/two-allocators-2.rs b/src/test/compile-fail/two-allocators-2.rs
deleted file mode 100644
index d6fcbcb513ae3..0000000000000
--- a/src/test/compile-fail/two-allocators-2.rs
+++ /dev/null
@@ -1,21 +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.
-
-// error-pattern: cannot link together two allocators: allocator1 and allocator2
-// aux-build:allocator1.rs
-// aux-build:allocator2.rs
-
-// Make sure we can't link together two explicit allocators.
-
-extern crate allocator1;
-extern crate allocator2;
-
-fn main() {}
-
diff --git a/src/test/compile-fail/two-allocators-3.rs b/src/test/compile-fail/two-allocators-3.rs
deleted file mode 100644
index 965e4e0e2eabe..0000000000000
--- a/src/test/compile-fail/two-allocators-3.rs
+++ /dev/null
@@ -1,23 +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.
-
-// aux-build:allocator1.rs
-// error-pattern: cannot link together two allocators
-// ignore-musl no dylibs on musl yet
-// ignore-emscripten
-
-// We're linking std dynamically (via -C prefer-dynamic for this test) which
-// has an allocator and then we're also linking in a new allocator (allocator1)
-// and this should be an error
-
-extern crate allocator1;
-
-fn main() {
-}
diff --git a/src/test/run-make/no-duplicate-libs/Makefile b/src/test/run-make/no-duplicate-libs/Makefile
index 3f6a28c251a2f..13d8366c60ab9 100644
--- a/src/test/run-make/no-duplicate-libs/Makefile
+++ b/src/test/run-make/no-duplicate-libs/Makefile
@@ -4,9 +4,7 @@ ifdef IS_MSVC
 # FIXME(#27979)
 all:
 else
-all:
-	$(RUSTC) foo.rs
-	$(RUSTC) bar.rs
+all: $(call STATICLIB,foo) $(call STATICLIB,bar)
 	$(RUSTC) main.rs
 	$(call RUN,main)
 endif
diff --git a/src/test/compile-fail/feature-gate-allocator.rs b/src/test/run-make/no-duplicate-libs/bar.c
similarity index 76%
rename from src/test/compile-fail/feature-gate-allocator.rs
rename to src/test/run-make/no-duplicate-libs/bar.c
index 6490216d0126f..b9dcd0f5e5eeb 100644
--- a/src/test/compile-fail/feature-gate-allocator.rs
+++ b/src/test/run-make/no-duplicate-libs/bar.c
@@ -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,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allocator] //~ ERROR: experimental feature
+extern void foo();
 
-fn main() {}
+void bar() {
+  foo();
+}
diff --git a/src/test/run-make/no-duplicate-libs/bar.rs b/src/test/run-make/no-duplicate-libs/bar.rs
deleted file mode 100644
index cb1c88689a89d..0000000000000
--- a/src/test/run-make/no-duplicate-libs/bar.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 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(lang_items, alloc_system, compiler_builtins_lib)]
-#![crate_type = "dylib"]
-#![no_std]
-
-extern crate alloc_system;
-extern crate compiler_builtins;
-
-#[no_mangle]
-pub extern fn bar() {}
-
-#[lang = "eh_personality"] fn eh_personality() {}
-#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-#[no_mangle] pub extern fn rust_eh_register_frames () {}
-#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
diff --git a/src/test/compile-fail/auxiliary/allocator-dylib2.rs b/src/test/run-make/no-duplicate-libs/foo.c
similarity index 83%
rename from src/test/compile-fail/auxiliary/allocator-dylib2.rs
rename to src/test/run-make/no-duplicate-libs/foo.c
index 0d76c0e5eb8d1..906cd5682b82d 100644
--- a/src/test/compile-fail/auxiliary/allocator-dylib2.rs
+++ b/src/test/run-make/no-duplicate-libs/foo.c
@@ -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,5 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub fn foo() {}
-
+void foo() {}
diff --git a/src/test/run-make/no-duplicate-libs/foo.rs b/src/test/run-make/no-duplicate-libs/foo.rs
deleted file mode 100644
index 214fb156c2d63..0000000000000
--- a/src/test/run-make/no-duplicate-libs/foo.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 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(lang_items, alloc_system, compiler_builtins_lib)]
-#![no_std]
-#![crate_type = "dylib"]
-
-extern crate alloc_system;
-extern crate compiler_builtins;
-
-#[no_mangle]
-pub extern fn foo() {}
-
-#[lang = "eh_personality"] fn eh_personality() {}
-#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-#[no_mangle] pub extern fn rust_eh_register_frames () {}
-#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
diff --git a/src/test/run-make/no-duplicate-libs/main.rs b/src/test/run-make/no-duplicate-libs/main.rs
index 12ddce345820b..824946fe9c2bd 100644
--- a/src/test/run-make/no-duplicate-libs/main.rs
+++ b/src/test/run-make/no-duplicate-libs/main.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[link(name = "foo")]
-#[link(name = "bar")]
-#[link(name = "foo")]
+#[link(name = "foo")] // linker should drop this library, no symbols used
+#[link(name = "bar")] // symbol comes from this library
+#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it
 extern {
     fn bar();
 }
diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
index 0433b95865ef8..e2c68a626f91e 100644
--- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
@@ -8,50 +8,37 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(unused_parens)]
-#![feature(plugin)]
-#![feature(plugin_registrar)]
-#![feature(rustc_private)]
-#![plugin(proc_macro_plugin)]
+// no-prefer-dynamic
 
-extern crate rustc_plugin;
-extern crate syntax;
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
 
-use rustc_plugin::Registry;
+extern crate proc_macro;
 
-use syntax::ext::base::SyntaxExtension;
-use syntax::parse::token::Token;
-use syntax::symbol::Symbol;
-use syntax::tokenstream::{TokenTree, TokenStream};
+use proc_macro::{TokenStream, TokenNode, quote};
 
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(Symbol::intern("cond"),
-                                  SyntaxExtension::ProcMacro(Box::new(cond)));
-}
-
-fn cond(input: TokenStream) -> TokenStream {
+#[proc_macro]
+pub fn cond(input: TokenStream) -> TokenStream {
     let mut conds = Vec::new();
-    let mut input = input.trees().peekable();
+    let mut input = input.into_iter().peekable();
     while let Some(tree) = input.next() {
-        let mut cond = match tree {
-            TokenTree::Delimited(_, ref delimited) => delimited.stream(),
+        let cond = match tree.kind {
+            TokenNode::Group(_, cond) => cond,
             _ => panic!("Invalid input"),
         };
-        let mut trees = cond.trees();
-        let test = trees.next();
-        let rhs = trees.collect::<TokenStream>();
+        let mut cond_trees = cond.clone().into_iter();
+        let test = cond_trees.next().expect("Unexpected empty condition in `cond!`");
+        let rhs = cond_trees.collect::<TokenStream>();
         if rhs.is_empty() {
             panic!("Invalid macro usage in cond: {}", cond);
         }
-        let is_else = match test {
-            Some(TokenTree::Token(_, Token::Ident(ident))) if ident.name == "else" => true,
+        let is_else = match test.kind {
+            TokenNode::Term(word) => word.as_str() == "else",
             _ => false,
         };
         conds.push(if is_else || input.peek().is_none() {
             quote!({ $rhs })
         } else {
-            let test = test.unwrap();
             quote!(if $test { $rhs } else)
         });
     }
diff --git a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
index 9522592a5e9e6..cf6584e961a67 100644
--- a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
@@ -8,29 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(plugin)]
-#![feature(plugin_registrar)]
-#![feature(rustc_private)]
-#![plugin(proc_macro_plugin)]
+// no-prefer-dynamic
 
-extern crate rustc_plugin;
-extern crate syntax;
+#![crate_type = "proc-macro"]
+#![feature(proc_macro, proc_macro_lib)]
 
-use rustc_plugin::Registry;
-use syntax::ext::base::SyntaxExtension;
-use syntax::symbol::Symbol;
-use syntax::tokenstream::TokenStream;
+extern crate proc_macro;
 
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(Symbol::intern("hello"),
-                                  SyntaxExtension::ProcMacro(Box::new(hello)));
-}
+use proc_macro::{TokenStream, quote};
 
 // This macro is not very interesting, but it does contain delimited tokens with
 // no content - `()` and `{}` - which has caused problems in the past.
 // Also, it tests that we can escape `$` via `$$`.
-fn hello(_: TokenStream) -> TokenStream {
+#[proc_macro]
+pub fn hello(_: TokenStream) -> TokenStream {
     quote!({
         fn hello() {}
         macro_rules! m { ($$($$t:tt)*) => { $$($$t)* } }
diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
index 0e37a7a5dcce2..1b47043884844 100644
--- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
@@ -8,47 +8,37 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(plugin, plugin_registrar, rustc_private)]
-#![plugin(proc_macro_plugin)]
-
-extern crate rustc_plugin;
-extern crate syntax;
-
-use rustc_plugin::Registry;
-use syntax::ext::base::SyntaxExtension;
-use syntax::tokenstream::TokenStream;
-use syntax::symbol::Symbol;
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(Symbol::intern("attr_tru"),
-                                  SyntaxExtension::AttrProcMacro(Box::new(attr_tru)));
-    reg.register_syntax_extension(Symbol::intern("attr_identity"),
-                                  SyntaxExtension::AttrProcMacro(Box::new(attr_identity)));
-    reg.register_syntax_extension(Symbol::intern("tru"),
-                                  SyntaxExtension::ProcMacro(Box::new(tru)));
-    reg.register_syntax_extension(Symbol::intern("ret_tru"),
-                                  SyntaxExtension::ProcMacro(Box::new(ret_tru)));
-    reg.register_syntax_extension(Symbol::intern("identity"),
-                                  SyntaxExtension::ProcMacro(Box::new(identity)));
-}
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro, proc_macro_lib)]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, quote};
 
-fn attr_tru(_attr: TokenStream, _item: TokenStream) -> TokenStream {
-    quote!(fn f1() -> bool { true })
+#[proc_macro_attribute]
+pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    let name = item.into_iter().skip(1).next().unwrap();
+    quote!(fn $name() -> bool { true })
 }
 
-fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
+#[proc_macro_attribute]
+pub fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
     quote!($item)
 }
 
-fn tru(_ts: TokenStream) -> TokenStream {
+#[proc_macro]
+pub fn tru(_ts: TokenStream) -> TokenStream {
     quote!(true)
 }
 
-fn ret_tru(_ts: TokenStream) -> TokenStream {
+#[proc_macro]
+pub fn ret_tru(_ts: TokenStream) -> TokenStream {
     quote!(return true;)
 }
 
-fn identity(ts: TokenStream) -> TokenStream {
+#[proc_macro]
+pub fn identity(ts: TokenStream) -> TokenStream {
     quote!($ts)
 }
diff --git a/src/test/run-pass-fulldeps/macro-quote-1.rs b/src/test/run-pass-fulldeps/macro-quote-1.rs
deleted file mode 100644
index e7d0a83017be0..0000000000000
--- a/src/test/run-pass-fulldeps/macro-quote-1.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012-2014 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.
-
-// ignore-stage1
-
-#![feature(plugin)]
-#![feature(rustc_private)]
-#![plugin(proc_macro_plugin)]
-
-extern crate syntax;
-extern crate syntax_pos;
-
-use syntax::ast::{Ident, Name};
-use syntax::parse::token::{self, Token, Lit};
-use syntax::tokenstream::TokenTree;
-
-fn main() {
-    let true_tok = token::Ident(Ident::from_str("true"));
-    assert!(quote!(true).eq_unspanned(&true_tok.into()));
-
-    // issue #35829, extended check to proc_macro.
-    let triple_dot_tok = Token::DotDotDot;
-    assert!(quote!(...).eq_unspanned(&triple_dot_tok.into()));
-
-    let byte_str_tok = Token::Literal(Lit::ByteStr(Name::intern("one")), None);
-    assert!(quote!(b"one").eq_unspanned(&byte_str_tok.into()));
-
-    let byte_str_raw_tok = Token::Literal(Lit::ByteStrRaw(Name::intern("#\"two\"#"), 3), None);
-    assert!(quote!(br###"#"two"#"###).eq_unspanned(&byte_str_raw_tok.into()));
-
-    let str_raw_tok = Token::Literal(Lit::StrRaw(Name::intern("#\"three\"#"), 2), None);
-    assert!(quote!(r##"#"three"#"##).eq_unspanned(&str_raw_tok.into()));
-}
diff --git a/src/test/run-pass-fulldeps/macro-quote-cond.rs b/src/test/run-pass-fulldeps/macro-quote-cond.rs
index fa969b6a087cf..cff743bdae6cd 100644
--- a/src/test/run-pass-fulldeps/macro-quote-cond.rs
+++ b/src/test/run-pass-fulldeps/macro-quote-cond.rs
@@ -11,9 +11,11 @@
 // aux-build:cond_plugin.rs
 // ignore-stage1
 
-#![feature(plugin)]
-#![feature(rustc_private)]
-#![plugin(cond_plugin)]
+#![feature(proc_macro)]
+
+extern crate cond_plugin;
+
+use cond_plugin::cond;
 
 fn fact(n : i64) -> i64 {
     if n == 0 {
diff --git a/src/test/run-pass-fulldeps/macro-quote-test.rs b/src/test/run-pass-fulldeps/macro-quote-test.rs
index bdbea8a419416..eb77895e2d7ad 100644
--- a/src/test/run-pass-fulldeps/macro-quote-test.rs
+++ b/src/test/run-pass-fulldeps/macro-quote-test.rs
@@ -13,10 +13,10 @@
 // aux-build:hello_macro.rs
 // ignore-stage1
 
-#![feature(plugin)]
-#![feature(rustc_private)]
-#![plugin(hello_macro)]
+#![feature(proc_macro)]
+
+extern crate hello_macro;
 
 fn main() {
-    hello!();
+    hello_macro::hello!();
 }
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs
index 989c77f1089cf..93815d16837d3 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs
@@ -24,7 +24,7 @@ pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream {
 
     let input = input.to_string();
 
-    assert_eq!(input, "fn foo (  ) {  }");
+    assert_eq!(input, "fn foo() { }");
 
     r#"
         fn foo() -> &'static str { "Hello, world!" }
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
new file mode 100644
index 0000000000000..ec2ff0d1e2b8c
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
@@ -0,0 +1,36 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenNode, Spacing, Literal, quote};
+
+#[proc_macro]
+pub fn count_compound_ops(input: TokenStream) -> TokenStream {
+    assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3);
+    TokenNode::Literal(Literal::u32(count_compound_ops_helper(input))).into()
+}
+
+fn count_compound_ops_helper(input: TokenStream) -> u32 {
+    let mut count = 0;
+    for token in input {
+        match token.kind {
+            TokenNode::Op(c, Spacing::Alone) => count += 1,
+            TokenNode::Group(_, tokens) => count += count_compound_ops_helper(tokens),
+            _ => {}
+        }
+    }
+    count
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs
new file mode 100644
index 0000000000000..8ffa7abe6f7f9
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs
@@ -0,0 +1,19 @@
+// 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(proc_macro)]
+
+extern crate hygiene_example_codegen;
+
+pub use hygiene_example_codegen::hello;
+
+pub fn print(string: &str) {
+    println!("{}", string);
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs
new file mode 100644
index 0000000000000..055e4e2fad7af
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs
@@ -0,0 +1,36 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
+
+use proc_macro_renamed::{TokenStream, quote};
+
+#[proc_macro]
+pub fn hello(input: TokenStream) -> TokenStream {
+    quote!(hello_helper!($input))
+    //^ `hello_helper!` always resolves to the following proc macro,
+    //| no matter where `hello!` is used.
+}
+
+#[proc_macro]
+pub fn hello_helper(input: TokenStream) -> TokenStream {
+    quote! {
+        extern crate hygiene_example; // This is never a conflict error
+        let string = format!("hello {}", $input);
+        //^ `format!` always resolves to the prelude macro,
+        //| even if a different `format!` is in scope where `hello!` is used.
+        hygiene_example::print(&string)
+    }
+}
diff --git a/src/test/run-pass/allocator-default.rs b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
similarity index 60%
rename from src/test/run-pass/allocator-default.rs
rename to src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
index 0a02e8072b9b3..1a2b144e4717b 100644
--- a/src/test/run-pass/allocator-default.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.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,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(alloc_jemalloc)]
+// aux-build:count_compound_ops.rs
 
-#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-          target_os = "macos"))]
-extern crate alloc_jemalloc;
+#![feature(proc_macro)]
+
+extern crate count_compound_ops;
+use count_compound_ops::count_compound_ops;
 
 fn main() {
-    println!("{:?}", Box::new(3));
+    assert_eq!(count_compound_ops!(foo<=>bar <<<! -baz ++), 4);
 }
diff --git a/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs
new file mode 100644
index 0000000000000..51198db5aa76d
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs
@@ -0,0 +1,27 @@
+// 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.
+
+// aux-build:hygiene_example_codegen.rs
+// aux-build:hygiene_example.rs
+
+#![feature(proc_macro)]
+
+extern crate hygiene_example;
+use hygiene_example::hello;
+
+fn main() {
+    mod hygiene_example {} // no conflict with `extern crate hygiene_example;` from the proc macro
+    macro_rules! format { () => {} } // does not interfere with `format!` from the proc macro
+    macro_rules! hello_helper { () => {} } // similarly does not intefere with the proc macro
+
+    let string = "world"; // no conflict with `string` from the proc macro
+    hello!(string);
+    hello!(string);
+}
diff --git a/src/test/run-pass-fulldeps/proc_macro.rs b/src/test/run-pass-fulldeps/proc_macro.rs
index 22cc9f0f8d40e..cdda723585b7a 100644
--- a/src/test/run-pass-fulldeps/proc_macro.rs
+++ b/src/test/run-pass-fulldeps/proc_macro.rs
@@ -12,10 +12,11 @@
 // ignore-stage1
 // ignore-cross-compile
 
-#![feature(plugin, custom_attribute)]
-#![feature(type_macros)]
+#![feature(proc_macro)]
 
-#![plugin(proc_macro_def)]
+extern crate proc_macro_def;
+
+use proc_macro_def::{attr_tru, attr_identity, identity, ret_tru, tru};
 
 #[attr_tru]
 fn f1() -> bool {
diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs
index 7cc547dcc04e2..712fa2d600177 100644
--- a/src/test/run-pass/allocator-alloc-one.rs
+++ b/src/test/run-pass/allocator-alloc-one.rs
@@ -8,20 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(alloc, allocator_api, heap_api, unique)]
+#![feature(allocator_api, unique)]
 
-extern crate alloc;
-
-use alloc::heap::HeapAlloc;
-use alloc::allocator::Alloc;
+use std::heap::{Heap, Alloc};
 
 fn main() {
     unsafe {
-        let ptr = HeapAlloc.alloc_one::<i32>().unwrap_or_else(|e| {
-            HeapAlloc.oom(e)
+        let ptr = Heap.alloc_one::<i32>().unwrap_or_else(|e| {
+            Heap.oom(e)
         });
         *ptr.as_ptr() = 4;
         assert_eq!(*ptr.as_ptr(), 4);
-        HeapAlloc.dealloc_one(ptr);
+        Heap.dealloc_one(ptr);
     }
 }
diff --git a/src/test/run-pass/allocator-override.rs b/src/test/run-pass/allocator-override.rs
deleted file mode 100644
index ca2dbdf2b3de3..0000000000000
--- a/src/test/run-pass/allocator-override.rs
+++ /dev/null
@@ -1,29 +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.
-
-// no-prefer-dynamic
-// aux-build:allocator-dummy.rs
-// ignore-emscripten
-
-#![feature(test)]
-
-extern crate allocator_dummy;
-extern crate test;
-
-fn main() {
-    unsafe {
-        let before = allocator_dummy::HITS;
-        let mut b = Box::new(3);
-        test::black_box(&mut b); // Make sure the allocation is not optimized away
-        assert_eq!(allocator_dummy::HITS - before, 1);
-        drop(b);
-        assert_eq!(allocator_dummy::HITS - before, 2);
-    }
-}
diff --git a/src/test/compile-fail/auxiliary/allocator2.rs b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs
similarity index 58%
rename from src/test/compile-fail/auxiliary/allocator2.rs
rename to src/test/run-pass/allocator/auxiliary/custom-as-global.rs
index b24784838d00b..538f36faadf2c 100644
--- a/src/test/compile-fail/auxiliary/allocator2.rs
+++ b/src/test/run-pass/allocator/auxiliary/custom-as-global.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.
 //
@@ -10,7 +10,18 @@
 
 // no-prefer-dynamic
 
-#![feature(allocator)]
-#![allocator]
+#![feature(global_allocator)]
 #![crate_type = "rlib"]
-#![no_std]
+
+extern crate custom;
+
+use std::sync::atomic::{ATOMIC_USIZE_INIT, Ordering};
+
+use custom::A;
+
+#[global_allocator]
+static ALLOCATOR: A = A(ATOMIC_USIZE_INIT);
+
+pub fn get() -> usize {
+    ALLOCATOR.0.load(Ordering::SeqCst)
+}
diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs
new file mode 100644
index 0000000000000..8f4fbcd5ab1c1
--- /dev/null
+++ b/src/test/run-pass/allocator/auxiliary/custom.rs
@@ -0,0 +1,31 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![feature(heap_api, allocator_api)]
+#![crate_type = "rlib"]
+
+use std::heap::{Alloc, System, AllocErr, Layout};
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+pub struct A(pub AtomicUsize);
+
+unsafe impl<'a> Alloc for &'a A {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        self.0.fetch_add(1, Ordering::SeqCst);
+        System.alloc(layout)
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        self.0.fetch_add(1, Ordering::SeqCst);
+        System.dealloc(ptr, layout)
+    }
+}
diff --git a/src/test/compile-fail/auxiliary/allocator1.rs b/src/test/run-pass/allocator/auxiliary/helper.rs
similarity index 77%
rename from src/test/compile-fail/auxiliary/allocator1.rs
rename to src/test/run-pass/allocator/auxiliary/helper.rs
index b24784838d00b..e75a432710df2 100644
--- a/src/test/compile-fail/auxiliary/allocator1.rs
+++ b/src/test/run-pass/allocator/auxiliary/helper.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.
 //
@@ -10,7 +10,10 @@
 
 // no-prefer-dynamic
 
-#![feature(allocator)]
-#![allocator]
 #![crate_type = "rlib"]
-#![no_std]
+
+use std::fmt;
+
+pub fn work_with(p: &fmt::Debug) {
+    drop(p);
+}
diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs
new file mode 100644
index 0000000000000..b46f024b5bff3
--- /dev/null
+++ b/src/test/run-pass/allocator/custom.rs
@@ -0,0 +1,68 @@
+// 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.
+
+// aux-build:helper.rs
+// no-prefer-dynamic
+
+#![feature(global_allocator, heap_api, allocator_api)]
+
+extern crate helper;
+
+use std::env;
+use std::heap::{Heap, Alloc, System, Layout, AllocErr};
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+
+static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
+
+struct A;
+
+unsafe impl<'a> Alloc for &'a A {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        HITS.fetch_add(1, Ordering::SeqCst);
+        System.alloc(layout)
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        HITS.fetch_add(1, Ordering::SeqCst);
+        System.dealloc(ptr, layout)
+    }
+}
+
+#[global_allocator]
+static GLOBAL: A = A;
+
+fn main() {
+    env::set_var("FOO", "bar");
+    drop(env::var("FOO"));
+
+    let n = HITS.load(Ordering::SeqCst);
+    assert!(n > 0);
+    unsafe {
+        let layout = Layout::from_size_align(4, 2).unwrap();
+
+        let ptr = Heap.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
+        Heap.dealloc(ptr, layout.clone());
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 2);
+
+        let s = String::with_capacity(10);
+        helper::work_with(&s);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 3);
+        drop(s);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
+
+        let ptr = System.alloc(layout.clone()).unwrap();
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
+        helper::work_with(&ptr);
+        System.dealloc(ptr, layout);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
+    }
+}
diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs
new file mode 100644
index 0000000000000..4b987b9223d6d
--- /dev/null
+++ b/src/test/run-pass/allocator/xcrate-use.rs
@@ -0,0 +1,44 @@
+// 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.
+
+// aux-build:custom.rs
+// aux-build:helper.rs
+// no-prefer-dynamic
+
+#![feature(global_allocator, heap_api, allocator_api)]
+
+extern crate custom;
+extern crate helper;
+
+use std::env;
+use std::heap::{Heap, Alloc, System, Layout};
+use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
+
+#[global_allocator]
+static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
+
+fn main() {
+    unsafe {
+        let n = GLOBAL.0.load(Ordering::SeqCst);
+        let layout = Layout::from_size_align(4, 2).unwrap();
+
+        let ptr = Heap.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
+        Heap.dealloc(ptr, layout.clone());
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+
+        let ptr = System.alloc(layout.clone()).unwrap();
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+        helper::work_with(&ptr);
+        System.dealloc(ptr, layout);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+    }
+}
diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs
new file mode 100644
index 0000000000000..7e6cd9fdf4950
--- /dev/null
+++ b/src/test/run-pass/allocator/xcrate-use2.rs
@@ -0,0 +1,57 @@
+// 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.
+
+// aux-build:custom.rs
+// aux-build:custom-as-global.rs
+// aux-build:helper.rs
+// no-prefer-dynamic
+
+#![feature(heap_api, allocator_api)]
+
+extern crate custom;
+extern crate custom_as_global;
+extern crate helper;
+
+use std::env;
+use std::heap::{Heap, Alloc, System, Layout};
+use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
+
+static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
+
+fn main() {
+    unsafe {
+        let n = custom_as_global::get();
+        let layout = Layout::from_size_align(4, 2).unwrap();
+
+        // Global allocator routes to the `custom_as_global` global
+        let ptr = Heap.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(custom_as_global::get(), n + 1);
+        Heap.dealloc(ptr, layout.clone());
+        assert_eq!(custom_as_global::get(), n + 2);
+
+        // Usage of the system allocator avoids all globals
+        let ptr = System.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(custom_as_global::get(), n + 2);
+        System.dealloc(ptr, layout.clone());
+        assert_eq!(custom_as_global::get(), n + 2);
+
+        // Usage of our personal allocator doesn't affect other instances
+        let ptr = (&GLOBAL).alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(custom_as_global::get(), n + 2);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1);
+        (&GLOBAL).dealloc(ptr, layout);
+        assert_eq!(custom_as_global::get(), n + 2);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2);
+    }
+}
+
diff --git a/src/test/run-pass/lib-defaults.rs b/src/test/run-pass/lib-defaults.rs
index a38080f8cfe75..6e5dccae0a07d 100644
--- a/src/test/run-pass/lib-defaults.rs
+++ b/src/test/run-pass/lib-defaults.rs
@@ -8,16 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:clibrary.rs
-// compile-flags: -lclibrary
+// compile-flags: -lrust_test_helpers
 
-#[link(name = "clibrary", kind = "static")]
+#[link(name = "rust_test_helpers", kind = "static")]
 extern "C" {
-    pub fn foo(x:i32) -> i32;
+    pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
 }
 
 fn main() {
     unsafe {
-        foo(42);
+        rust_dbg_extern_identity_u32(42);
     }
 }
diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs
index 372d4a8b732ac..f6119e709990a 100644
--- a/src/test/run-pass/range_inclusive.rs
+++ b/src/test/run-pass/range_inclusive.rs
@@ -10,7 +10,7 @@
 
 // Test inclusive range syntax.
 
-#![feature(inclusive_range_syntax, inclusive_range, step_by)]
+#![feature(inclusive_range_syntax, inclusive_range, iterator_step_by)]
 
 use std::ops::{RangeInclusive, RangeToInclusive};
 
diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs
index b32d42df6b129..eddcd5a584a5d 100644
--- a/src/test/run-pass/realloc-16687.rs
+++ b/src/test/run-pass/realloc-16687.rs
@@ -13,11 +13,9 @@
 // Ideally this would be revised to use no_std, but for now it serves
 // well enough to reproduce (and illustrate) the bug from #16687.
 
-#![feature(heap_api, alloc, oom)]
+#![feature(heap_api, allocator_api)]
 
-extern crate alloc;
-
-use alloc::heap;
+use std::heap::{Heap, Alloc, Layout};
 use std::ptr;
 
 fn main() {
@@ -47,38 +45,39 @@ unsafe fn test_triangle() -> bool {
 
     static PRINT : bool = false;
 
-    unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-        if PRINT { println!("allocate(size={} align={})", size, align); }
+    unsafe fn allocate(layout: Layout) -> *mut u8 {
+        if PRINT {
+            println!("allocate({:?})", layout);
+        }
 
-        let ret = heap::allocate(size, align);
-        if ret.is_null() { alloc::oom() }
+        let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e));
 
-        if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}",
-                            size, align, ret as usize);
+        if PRINT {
+            println!("allocate({:?}) = {:?}", layout, ret);
         }
 
         ret
     }
-    unsafe fn deallocate(ptr: *mut u8, size: usize, align: usize) {
-        if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})",
-                            ptr as usize, size, align);
+
+    unsafe fn deallocate(ptr: *mut u8, layout: Layout) {
+        if PRINT {
+            println!("deallocate({:?}, {:?}", ptr, layout);
         }
 
-        heap::deallocate(ptr, size, align);
+        Heap.dealloc(ptr, layout);
     }
-    unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
+
+    unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
         if PRINT {
-            println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})",
-                     ptr as usize, old_size, size, align);
+            println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
         }
 
-        let ret = heap::reallocate(ptr, old_size, size, align);
-        if ret.is_null() { alloc::oom() }
+        let ret = Heap.realloc(ptr, old.clone(), new.clone())
+            .unwrap_or_else(|e| Heap.oom(e));
 
         if PRINT {
-            println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \
-                      ret: 0x{:010x}",
-                     ptr as usize, old_size, size, align, ret as usize);
+            println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
+                     ptr, old, new, ret);
         }
         ret
     }
@@ -91,8 +90,8 @@ unsafe fn test_triangle() -> bool {
     // way.)
     for i in 0..COUNT / 2 {
         let size = idx_to_size(i);
-        ascend[2*i]   = allocate(size, ALIGN);
-        ascend[2*i+1] = allocate(size, ALIGN);
+        ascend[2*i]   = allocate(Layout::from_size_align(size, ALIGN).unwrap());
+        ascend[2*i+1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
     }
 
     // Initialize each pair of rows to distinct value.
@@ -112,8 +111,8 @@ unsafe fn test_triangle() -> bool {
 
     for i in 0..COUNT / 2 {
         let size = idx_to_size(i);
-        deallocate(ascend[2*i], size, ALIGN);
-        deallocate(ascend[2*i+1], size, ALIGN);
+        deallocate(ascend[2*i], Layout::from_size_align(size, ALIGN).unwrap());
+        deallocate(ascend[2*i+1], Layout::from_size_align(size, ALIGN).unwrap());
     }
 
     return true;
@@ -124,14 +123,16 @@ unsafe fn test_triangle() -> bool {
     // rows as we go.
     unsafe fn test_1(ascend: &mut [*mut u8]) {
         let new_size = idx_to_size(COUNT-1);
+        let new = Layout::from_size_align(new_size, ALIGN).unwrap();
         for i in 0..COUNT / 2 {
             let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(old_size < new_size);
+            let old = Layout::from_size_align(old_size, ALIGN).unwrap();
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
@@ -139,14 +140,16 @@ unsafe fn test_triangle() -> bool {
     // Test 2: turn the square back into a triangle, top to bottom.
     unsafe fn test_2(ascend: &mut [*mut u8]) {
         let old_size = idx_to_size(COUNT-1);
+        let old = Layout::from_size_align(old_size, ALIGN).unwrap();
         for i in 0..COUNT / 2 {
             let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(new_size < old_size);
+            let new = Layout::from_size_align(new_size, ALIGN).unwrap();
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
@@ -154,14 +157,16 @@ unsafe fn test_triangle() -> bool {
     // Test 3: turn triangle into a square, bottom to top.
     unsafe fn test_3(ascend: &mut [*mut u8]) {
         let new_size = idx_to_size(COUNT-1);
+        let new = Layout::from_size_align(new_size, ALIGN).unwrap();
         for i in (0..COUNT / 2).rev() {
             let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(old_size < new_size);
+            let old = Layout::from_size_align(old_size, ALIGN).unwrap();
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
@@ -169,14 +174,16 @@ unsafe fn test_triangle() -> bool {
     // Test 4: turn the square back into a triangle, bottom to top.
     unsafe fn test_4(ascend: &mut [*mut u8]) {
         let old_size = idx_to_size(COUNT-1);
+        let old = Layout::from_size_align(old_size, ALIGN).unwrap();
         for i in (0..COUNT / 2).rev() {
             let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(new_size < old_size);
+            let new = Layout::from_size_align(new_size, ALIGN).unwrap();
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
diff --git a/src/test/run-pass/rfc1717/library-override.rs b/src/test/run-pass/rfc1717/library-override.rs
index d6ef96c5add01..26713a2554377 100644
--- a/src/test/run-pass/rfc1717/library-override.rs
+++ b/src/test/run-pass/rfc1717/library-override.rs
@@ -8,16 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:clibrary.rs
-// compile-flags: -lstatic=wronglibrary:clibrary
+// compile-flags: -lstatic=wronglibrary:rust_test_helpers
 
 #[link(name = "wronglibrary", kind = "dylib")]
 extern "C" {
-    pub fn foo(x:i32) -> i32;
+    pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
 }
 
 fn main() {
     unsafe {
-        foo(42);
+        rust_dbg_extern_identity_u32(42);
     }
 }
diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs
index 053ee8ee42ed6..bcbd3fd3786ab 100644
--- a/src/test/run-pass/smallest-hello-world.rs
+++ b/src/test/run-pass/smallest-hello-world.rs
@@ -10,32 +10,32 @@
 
 // Smallest "hello world" with a libc runtime
 
-// pretty-expanded FIXME #23616
 // ignore-windows
+// ignore-android
 
 #![feature(intrinsics, lang_items, start, no_core, alloc_system)]
-#![no_core]
+#![feature(global_allocator, allocator_api)]
+#![no_std]
 
 extern crate alloc_system;
 
-extern { fn puts(s: *const u8); }
-extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }
+use alloc_system::System;
 
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
+#[global_allocator]
+static A: System = System;
+
+extern {
+    fn puts(s: *const u8);
+}
+
+#[no_mangle]
+#[lang = "eh_personality"] pub extern fn rust_eh_personality() {}
 #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-#[no_mangle] pub extern fn rust_eh_register_frames () {}
-#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
 
 #[start]
 fn main(_: isize, _: *const *const u8) -> isize {
     unsafe {
-        let (ptr, _): (*const u8, usize) = transmute("Hello!\0");
-        puts(ptr);
+        puts("Hello!\0".as_ptr() as *const u8);
     }
-    return 0;
+    return 0
 }
-
-#[cfg(target_os = "android")]
-#[link(name="gcc")]
-extern { }
diff --git a/src/test/run-pass/sync-send-iterators-in-libcore.rs b/src/test/run-pass/sync-send-iterators-in-libcore.rs
index d12bdf182fa4d..c11a0d391a469 100644
--- a/src/test/run-pass/sync-send-iterators-in-libcore.rs
+++ b/src/test/run-pass/sync-send-iterators-in-libcore.rs
@@ -14,7 +14,7 @@
 #![feature(iter_empty)]
 #![feature(iter_once)]
 #![feature(iter_unfold)]
-#![feature(step_by)]
+#![feature(iterator_step_by)]
 #![feature(str_escape)]
 
 use std::iter::{empty, once, repeat};
diff --git a/src/test/ui/token/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs
index 47374fc3c6085..08749373432f5 100644
--- a/src/test/ui/token/macro-incomplete-parse.rs
+++ b/src/test/ui/token/macro-incomplete-parse.rs
@@ -32,7 +32,7 @@ macro_rules! ignored_pat {
 ignored_item!(); //~ NOTE caused by the macro expansion here
 
 fn main() {
-    ignored_expr!();
+    ignored_expr!(); //~ NOTE in this expansion
     match 1 {
         ignored_pat!() => (), //~ NOTE caused by the macro expansion here
         _ => (),
diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr
index f23d97586b843..6bce09af05250 100644
--- a/src/test/ui/token/macro-incomplete-parse.stderr
+++ b/src/test/ui/token/macro-incomplete-parse.stderr
@@ -15,6 +15,9 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
    |
 22 |     () => ( 1,  //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
    |              ^ expected one of `.`, `;`, `?`, `}`, or an operator here
+...
+35 |     ignored_expr!(); //~ NOTE in this expansion
+   |     ---------------- in this macro invocation
 
 error: macro expansion ignores token `,` and any following
   --> $DIR/macro-incomplete-parse.rs:29:14
diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs
index c8c6cb0ee6b41..f40fea60f40a8 100644
--- a/src/tools/tidy/src/cargo.rs
+++ b/src/tools/tidy/src/cargo.rs
@@ -91,14 +91,6 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
             continue
         }
 
-        // We want the compiler to depend on the proc_macro_plugin crate so
-        // that it is built and included in the end, but we don't want to
-        // actually use it in the compiler.
-        if toml.contains("name = \"rustc_driver\"") &&
-           krate == "proc_macro_plugin" {
-            continue
-        }
-
         if !librs.contains(&format!("extern crate {}", krate)) {
             tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \
                               depends on it", libfile.display(), krate);
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 722fc2b317eb4..4c94ade98d965 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -245,7 +245,7 @@ fn get_and_check_lib_features(base_src_path: &Path,
                     let mut err = |msg: &str| {
                         tidy_error!(bad, "{}:{}: {}", file.display(), line, msg);
                     };
-                    if lang_features.contains_key(name) {
+                    if lang_features.contains_key(name) && name != "proc_macro" {
                         err("duplicating a lang feature");
                     }
                     if let Some(ref s) = lib_features.get(name) {
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index bcf86e4489be3..020570e61dc63 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -54,6 +54,7 @@ fn filter_dirs(path: &Path) -> bool {
         "src/jemalloc",
         "src/llvm",
         "src/libbacktrace",
+        "src/libcompiler_builtins",
         "src/compiler-rt",
         "src/rustllvm",
         "src/liblibc",