From 5a97036b6900ee208f90c52ceadcce606d497e93 Mon Sep 17 00:00:00 2001
From: Clar Charr <clar@charr.xyz>
Date: Sat, 20 May 2017 15:40:53 -0400
Subject: [PATCH 01/52] Convert Intos to Froms.

---
 src/liballoc/string.rs   | 6 +++---
 src/libstd/ffi/c_str.rs  | 6 +++---
 src/libstd/ffi/os_str.rs | 6 +++---
 src/libstd/path.rs       | 6 +++---
 4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 2cb81029f95e2..c1ef1c2f96c73 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -2009,9 +2009,9 @@ 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()
+impl From<String> for Box<str> {
+    fn from(s: String) -> Box<str> {
+        s.into_boxed_str()
     }
 }
 
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 1a91417ca0e92..1586e0a4ddbd3 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -586,10 +586,10 @@ impl From<Box<CStr>> for CString {
 }
 
 #[stable(feature = "box_from_c_string", since = "1.18.0")]
-impl Into<Box<CStr>> for CString {
+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 f54d79c201f48..3815f98668180 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -543,9 +543,9 @@ 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()
+impl From<OsString> for Box<OsStr> {
+    fn from(s: OsString) -> Box<OsStr> {
+        s.into_boxed_os_str()
     }
 }
 
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 42a54ed6d754c..e9bf7b33b8e42 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1349,9 +1349,9 @@ 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()
+impl From<PathBuf> for Box<Path> {
+    fn from(p: PathBuf) -> Box<Path> {
+        p.into_boxed_path()
     }
 }
 

From 0d885efe16899c2dbad2918345c9ede7b83caa7f Mon Sep 17 00:00:00 2001
From: Oliver Middleton <olliemail27@gmail.com>
Date: Tue, 13 Jun 2017 00:08:37 +0100
Subject: [PATCH 02/52] Update version numbers for From impls

---
 src/liballoc/string.rs   | 2 +-
 src/libstd/ffi/c_str.rs  | 2 +-
 src/libstd/ffi/os_str.rs | 2 +-
 src/libstd/path.rs       | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index c1ef1c2f96c73..02ecb65fa38ff 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -2008,7 +2008,7 @@ impl From<Box<str>> for String {
     }
 }
 
-#[stable(feature = "box_from_str", since = "1.18.0")]
+#[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/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 1586e0a4ddbd3..5f0b11a616eb0 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -585,7 +585,7 @@ impl From<Box<CStr>> for CString {
     }
 }
 
-#[stable(feature = "box_from_c_string", since = "1.18.0")]
+#[stable(feature = "box_from_c_string", since = "1.20.0")]
 impl From<CString> for Box<CStr> {
     #[inline]
     fn from(s: CString) -> Box<CStr> {
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 3815f98668180..3232a51546e72 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -542,7 +542,7 @@ impl From<Box<OsStr>> for OsString {
     }
 }
 
-#[stable(feature = "box_from_os_string", since = "1.18.0")]
+#[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/path.rs b/src/libstd/path.rs
index e9bf7b33b8e42..7a8c89353940a 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1348,7 +1348,7 @@ impl From<Box<Path>> for PathBuf {
     }
 }
 
-#[stable(feature = "box_from_path_buf", since = "1.18.0")]
+#[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()

From d4488b7df97e62bfeed8c30b1922ce55ff254594 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Tue, 28 Mar 2017 05:32:43 +0000
Subject: [PATCH 03/52] Simplify `hygiene::Mark` application, and remove
 variant `Token::SubstNt` in favor of `quoted::TokenTree::MetaVar`.

---
 src/libproc_macro/lib.rs                    | 28 +++++-----
 src/librustc/ich/impls_syntax.rs            |  3 +-
 src/librustc_metadata/cstore_impl.rs        |  2 +-
 src/librustdoc/html/highlight.rs            |  2 +-
 src/libsyntax/ext/base.rs                   | 14 -----
 src/libsyntax/ext/expand.rs                 | 36 ++++++-------
 src/libsyntax/ext/quote.rs                  |  4 +-
 src/libsyntax/ext/tt/macro_parser.rs        | 24 ++++-----
 src/libsyntax/ext/tt/macro_rules.rs         | 11 ++--
 src/libsyntax/ext/tt/quoted.rs              | 13 +++--
 src/libsyntax/ext/tt/transcribe.rs          | 60 ++++++++++++---------
 src/libsyntax/fold.rs                       |  1 -
 src/libsyntax/parse/lexer/mod.rs            | 42 ++++++++-------
 src/libsyntax/parse/mod.rs                  | 13 +++--
 src/libsyntax/parse/parser.rs               |  5 +-
 src/libsyntax/parse/token.rs                |  3 --
 src/libsyntax/print/pprust.rs               |  1 -
 src/libsyntax_ext/concat_idents.rs          |  7 ++-
 src/libsyntax_ext/deriving/custom.rs        | 15 ++----
 src/libsyntax_ext/format.rs                 | 13 +++--
 src/libsyntax_ext/proc_macro_impl.rs        |  4 +-
 src/libsyntax_pos/hygiene.rs                | 24 ++++-----
 src/libsyntax_pos/lib.rs                    |  2 +-
 src/test/compile-fail/asm-out-assign-imm.rs |  1 -
 src/test/compile-fail/macro-context.rs      |  2 +-
 src/test/ui/token/macro-incomplete-parse.rs |  2 +-
 26 files changed, 160 insertions(+), 172 deletions(-)

diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index f3d0521a2af6c..4744baf1b42fe 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -87,6 +87,8 @@ pub mod __internal {
     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_};
@@ -107,7 +109,7 @@ pub mod __internal {
     }
 
     pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
-        with_parse_sess(move |sess| {
+        with_sess(move |(sess, _)| {
             let mut parser = parse::stream_to_parser(sess, stream.inner);
             let mut items = Vec::new();
 
@@ -140,13 +142,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 +159,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) })
     }
 }
 
@@ -181,10 +184,11 @@ impl FromStr for TokenStream {
     type Err = LexError;
 
     fn from_str(src: &str) -> Result<TokenStream, LexError> {
-        __internal::with_parse_sess(|sess| {
+        __internal::with_sess(|(sess, mark)| {
             let src = src.to_string();
             let name = "<proc-macro source code>".to_string();
-            let stream = parse::parse_stream_from_source_str(name, src, sess);
+            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))
         })
     }
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_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index c49712086d52c..0649553e382e3 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -372,7 +372,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/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index a40d1e6bdc917..1f8c88d8ecf96 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/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 8089fad5f36d8..af5eabf06f87b 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -903,17 +903,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/expand.rs b/src/libsyntax/ext/expand.rs
index f8a26287bd47b..11efef4549976 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -16,7 +16,7 @@ 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;
@@ -470,7 +470,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 +477,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 +486,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 +505,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 +540,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 +616,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 +667,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);
@@ -787,12 +783,12 @@ fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream {
         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)
+    string_to_stream(text, parse_sess, item.span())
 }
 
-fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream {
+fn string_to_stream(text: String, parse_sess: &ParseSess, span: Span) -> TokenStream {
     let filename = String::from("<macro expansion>");
-    filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text))
+    filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text), Some(span))
 }
 
 impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
@@ -1070,7 +1066,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..314a97496f8cc 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -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 fa65e9501c2bb..18056f6028745 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: Symbol::intern("$crate"), ..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..9438e2fb0e5bf 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/fold.rs b/src/libsyntax/fold.rs
index 4c6cf49a8db43..2032aecacbb91 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -588,7 +588,6 @@ pub fn noop_fold_token<T: Folder>(t: token::Token, fld: &mut T) -> token::Token
             };
             token::Interpolated(Rc::new(fld.fold_interpolated(nt)))
         }
-        token::SubstNt(ident) => token::SubstNt(fld.fold_ident(ident)),
         _ => t
     }
 }
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index e2656bea48339..afc1e583d69bb 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);
                 };
             }
         }
@@ -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/mod.rs b/src/libsyntax/parse/mod.rs
index 3a68a6ba7646c..f917eec2cd0b1 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())
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 851a638e14842..25ab46f6f9e2b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2626,7 +2626,10 @@ 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
             }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 77db604c56e11..f208b0f56f81e 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -172,9 +172,6 @@ pub enum Token {
     // 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
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 34cda433d5250..6c6ca556e35ed 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -270,7 +270,6 @@ 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(),
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/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/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/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
         _ => (),

From 7d41674b175cdb3452e042ef6f37141bc3788f8b Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 17 Mar 2017 23:23:12 +0000
Subject: [PATCH 04/52] Clean up `tokenstream::Cursor` and `proc_macro`.

---
 src/libproc_macro/lib.rs     | 28 ++++++++-----------
 src/libsyntax/tokenstream.rs | 54 ++++++++++++++++++------------------
 2 files changed, 38 insertions(+), 44 deletions(-)

diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 4744baf1b42fe..b9f4fa63e6006 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -48,7 +48,7 @@ use std::str::FromStr;
 
 use syntax::errors::DiagnosticBuilder;
 use syntax::parse;
-use syntax::tokenstream::TokenStream as TokenStream_;
+use syntax::tokenstream;
 
 /// The main type provided by this crate, representing an abstract stream of
 /// tokens.
@@ -60,9 +60,7 @@ 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_,
-}
+pub struct TokenStream(tokenstream::TokenStream);
 
 /// Error returned from `TokenStream::from_str`.
 #[derive(Debug)]
@@ -91,26 +89,22 @@ pub mod __internal {
     use syntax::ext::hygiene::Mark;
     use syntax::ptr::P;
     use syntax::parse::{self, token, ParseSess};
-    use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_};
+    use syntax::tokenstream;
 
     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 (span, token) = (item.span, token::Interpolated(Rc::new(token::NtItem(item))));
+        TokenStream(tokenstream::TokenTree::Token(span, 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_sess(move |(sess, _)| {
-            let mut parser = parse::stream_to_parser(sess, stream.inner);
+            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)) {
@@ -121,8 +115,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 {
@@ -197,6 +191,6 @@ impl FromStr for TokenStream {
 #[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)
+        self.0.fmt(f)
     }
 }
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 963482fc223f1..ab4f697071477 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -199,7 +199,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)),
         }
     }
@@ -244,37 +244,22 @@ struct StreamCursor {
     stack: Vec<(RcSlice<TokenStream>, usize)>,
 }
 
-impl Iterator for Cursor {
-    type Item = TokenTree;
-
+impl StreamCursor {
     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,
-        };
-
         loop {
-            if cursor.index < cursor.stream.len() {
-                match cursor.stream[cursor.index].kind.clone() {
-                    TokenStreamKind::Tree(tree) => {
-                        cursor.index += 1;
-                        return Some(tree);
-                    }
+            if self.index < self.stream.len() {
+                self.index += 1;
+                match self.stream[self.index - 1].kind.clone() {
+                    TokenStreamKind::Tree(tree) => 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;
+                        self.stack.push((mem::replace(&mut self.stream, stream),
+                                         mem::replace(&mut self.index, 0)));
                     }
+                    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;
             }
@@ -282,6 +267,21 @@ impl Iterator for Cursor {
     }
 }
 
+impl Iterator for Cursor {
+    type Item = TokenTree;
+
+    fn next(&mut self) -> Option<TokenTree> {
+        let (tree, consumed) = match self.0 {
+            CursorKind::Tree(ref tree, ref mut consumed @ false) => (tree, consumed),
+            CursorKind::Stream(ref mut cursor) => return cursor.next(),
+            _ => return None,
+        };
+
+        *consumed = true;
+        Some(tree.clone())
+    }
+}
+
 impl Cursor {
     fn new(stream: TokenStream) -> Self {
         Cursor(match stream.kind {

From e42836b2085233323339bacb636ecf9c28e8422e Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 17 Mar 2017 23:41:09 +0000
Subject: [PATCH 05/52] Implement `quote!` and other `proc_macro` API.

---
 src/Cargo.lock                                |   9 -
 .../src/library-features/proc-macro.md        |   7 +
 src/libproc_macro/Cargo.toml                  |   1 +
 src/libproc_macro/lib.rs                      | 474 +++++++++++++++++-
 src/libproc_macro/quote.rs                    | 259 ++++++++++
 src/libproc_macro_plugin/Cargo.toml           |  13 -
 src/libproc_macro_plugin/lib.rs               | 103 ----
 src/libproc_macro_plugin/quote.rs             | 230 ---------
 src/librustc/hir/map/definitions.rs           |  27 +-
 src/librustc/middle/stability.rs              |   1 +
 src/librustc_driver/Cargo.toml                |   1 -
 src/librustc_metadata/creader.rs              |  48 +-
 src/librustc_metadata/cstore_impl.rs          |   5 +
 src/librustc_metadata/decoder.rs              |   2 +-
 src/librustc_metadata/encoder.rs              |   7 +-
 src/libsyntax/ast.rs                          |   8 +-
 src/libsyntax/ext/base.rs                     |   5 +-
 src/libsyntax/ext/build.rs                    |   2 +-
 src/libsyntax/feature_gate.rs                 |  28 +-
 src/libsyntax/fold.rs                         |   2 +-
 src/libsyntax/parse/lexer/tokentrees.rs       |  12 +-
 src/libsyntax/parse/parser.rs                 |   4 +-
 src/libsyntax/parse/token.rs                  |  63 +++
 src/libsyntax/tokenstream.rs                  | 152 +++++-
 src/libsyntax/util/rc_slice.rs                |  10 +-
 .../auxiliary/cond_plugin.rs                  |  43 +-
 .../auxiliary/hello_macro.rs                  |  23 +-
 .../auxiliary/proc_macro_def.rs               |  50 +-
 src/test/run-pass-fulldeps/macro-quote-1.rs   |  40 --
 .../run-pass-fulldeps/macro-quote-cond.rs     |   8 +-
 .../run-pass-fulldeps/macro-quote-test.rs     |   8 +-
 src/test/run-pass-fulldeps/proc_macro.rs      |   7 +-
 src/tools/tidy/src/cargo.rs                   |   8 -
 src/tools/tidy/src/features.rs                |   2 +-
 34 files changed, 1085 insertions(+), 577 deletions(-)
 create mode 100644 src/doc/unstable-book/src/library-features/proc-macro.md
 create mode 100644 src/libproc_macro/quote.rs
 delete mode 100644 src/libproc_macro_plugin/Cargo.toml
 delete mode 100644 src/libproc_macro_plugin/lib.rs
 delete mode 100644 src/libproc_macro_plugin/quote.rs
 delete mode 100644 src/test/run-pass-fulldeps/macro-quote-1.rs

diff --git a/src/Cargo.lock b/src/Cargo.lock
index dd6e72a56149e..e8f0ed6ed2c18 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -882,14 +882,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",
 ]
 
@@ -1210,7 +1202,6 @@ 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_back 0.0.0",
  "rustc_borrowck 0.0.0",
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/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 b9f4fa63e6006..f1abd3339ed53 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -37,18 +37,24 @@
        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)]
 
 extern crate syntax;
+extern crate syntax_pos;
 
-use std::fmt;
+use std::{fmt, iter, ops};
 use std::str::FromStr;
 
+use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
-use syntax::parse;
+use syntax::parse::{self, token};
+use syntax::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,6 +66,7 @@ use syntax::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")]
+#[derive(Clone)]
 pub struct TokenStream(tokenstream::TokenStream);
 
 /// Error returned from `TokenStream::from_str`.
@@ -69,6 +76,443 @@ 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", issue = "38356")]
+impl From<TokenTree> for TokenStream {
+    fn from(tree: TokenTree) -> TokenStream {
+        TokenStream(tree.to_raw())
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<TokenKind> for TokenStream {
+    fn from(kind: TokenKind) -> 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::TokenStream::builder();
+        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 = TokenIter;
+
+    fn into_iter(self) -> TokenIter {
+        TokenIter { 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)]
+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
+        }))
+    }
+}
+
+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)]
+pub struct TokenTree {
+    /// The `TokenTree`'s span
+    pub span: Span,
+    /// Description of the `TokenTree`
+    pub kind: TokenKind,
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<TokenKind> for TokenTree {
+    fn from(kind: TokenKind) -> 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)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub enum TokenKind {
+    /// A delimited tokenstream.
+    Sequence(Delimiter, TokenStream),
+    /// A unicode identifier.
+    Word(Symbol),
+    /// A punctuation character (`+`, `,`, `$`, etc.).
+    Op(char, OpKind),
+    /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
+    Literal(Literal),
+}
+
+/// Describes how a sequence of token trees is delimited.
+#[derive(Copy, Clone)]
+#[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)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub struct Symbol(symbol::Symbol);
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl<'a> From<&'a str> for Symbol {
+    fn from(string: &'a str) -> Symbol {
+        Symbol(symbol::Symbol::intern(string))
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl ops::Deref for Symbol {
+    type Target = str;
+
+    fn deref(&self) -> &str {
+        unsafe { &*(self.0.as_str().deref() as *const str) }
+    }
+}
+
+/// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
+#[derive(Copy, Clone)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub enum OpKind {
+    /// e.g. `+` is `Alone` in `+ =`.
+    Alone,
+    /// e.g. `+` is `Joint` in `+=`.
+    Joint,
+}
+
+/// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
+#[derive(Clone)]
+#[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: TokenKind::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::integer(n as i128, stringify!($int_kind))
+        }
+    )*}
+}
+
+impl Literal {
+    int_literals!(u8, i8, u16, i16, u32, i32, u64, i64);
+    fn integer(n: i128, kind: &'static str) -> Literal {
+        Literal(token::Literal(token::Lit::Integer(symbol::Symbol::intern(&n.to_string())),
+                               Some(symbol::Symbol::intern(kind))))
+    }
+
+    /// Floating point literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn f32(n: f32) -> Literal {
+        Literal(token::Literal(token::Lit::Float(symbol::Symbol::intern(&n.to_string())),
+                               Some(symbol::Symbol::intern("f32"))))
+    }
+
+    /// Floating point literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn f64(n: f32) -> Literal {
+        Literal(token::Literal(token::Lit::Float(symbol::Symbol::intern(&n.to_string())),
+                               Some(symbol::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::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::Symbol::intern(&escaped)), None))
+    }
+}
+
+/// An iterator over `TokenTree`s.
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub struct TokenIter {
+    cursor: tokenstream::Cursor,
+    next: Option<tokenstream::TokenStream>,
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl Iterator for TokenIter {
+    type Item = TokenTree;
+
+    fn next(&mut self) -> Option<TokenTree> {
+        self.next.take().or_else(|| self.cursor.next_as_stream())
+            .map(|next| TokenTree::from_raw(next, &mut self.next))
+    }
+}
+
+impl Delimiter {
+    fn from_raw(delim: token::DelimToken) -> Delimiter {
+        match delim {
+            token::Paren => Delimiter::Parenthesis,
+            token::Brace => Delimiter::Brace,
+            token::Bracket => Delimiter::Bracket,
+            token::NoDelim => Delimiter::None,
+        }
+    }
+
+    fn to_raw(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_raw(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_raw(delimed.delim);
+                return TokenTree {
+                    span: Span(span),
+                    kind: TokenKind::Sequence(delimiter, TokenStream(delimed.tts.into())),
+                };
+            }
+        };
+
+        let op_kind = if is_joint { OpKind::Joint } else { OpKind::Alone };
+        macro_rules! op {
+            ($op:expr) => { TokenKind::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>)
+                 -> TokenKind {
+            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() });
+            TokenKind::Op(first, OpKind::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) => TokenKind::Word(Symbol(ident.name)),
+            Literal(..) | DocComment(..) => TokenKind::Literal(self::Literal(token)),
+
+            Interpolated(..) => unimplemented!(),
+
+            OpenDelim(..) | CloseDelim(..) => unreachable!(),
+            Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
+        };
+
+        TokenTree { span: Span(span), kind: kind }
+    }
+
+    fn to_raw(self) -> tokenstream::TokenStream {
+        use syntax::parse::token::*;
+        use syntax::tokenstream::{TokenTree, Delimited};
+
+        let (op, kind) = match self.kind {
+            TokenKind::Op(op, kind) => (op, kind),
+            TokenKind::Sequence(delimiter, tokens) => {
+                return TokenTree::Delimited(self.span.0, Delimited {
+                    delim: delimiter.to_raw(),
+                    tts: tokens.0.into(),
+                }).into();
+            },
+            TokenKind::Word(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();
+            }
+            TokenKind::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 {
+            OpKind::Alone => tree.into(),
+            OpKind::Joint => tree.joint(),
+        }
+    }
+}
+
 /// Permanently unstable internal implementation details of this crate. This
 /// should not be used.
 ///
@@ -80,7 +524,11 @@ pub struct LexError {
 /// all of the contents.
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
+#[path = ""]
 pub mod __internal {
+    mod quote;
+    pub use self::quote::{Quoter, __rt};
+
     use std::cell::Cell;
     use std::rc::Rc;
 
@@ -172,25 +620,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_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)
-    }
-}
diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs
new file mode 100644
index 0000000000000..a3ea3925fcd48
--- /dev/null
+++ b/src/libproc_macro/quote.rs
@@ -0,0 +1,259 @@
+// 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::ext::base::{ExtCtxt, ProcMacro};
+use syntax::parse::token::{self, Token, Lit};
+use syntax::symbol::Symbol;
+use syntax::tokenstream::{Delimited, TokenTree, TokenStream};
+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, 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
+}
+
+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 = TokenStream::builder();
+        builder.push(quote!(rt::TokenStream::builder()));
+
+        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/Cargo.toml b/src/libproc_macro_plugin/Cargo.toml
deleted file mode 100644
index 146a66cdf01cb..0000000000000
--- a/src/libproc_macro_plugin/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-name = "proc_macro_plugin"
-version = "0.0.0"
-
-[lib]
-path = "lib.rs"
-crate-type = ["dylib"]
-
-[dependencies]
-rustc_plugin = { path = "../librustc_plugin" }
-syntax = { path = "../libsyntax" }
-syntax_pos = { path = "../libsyntax_pos" }
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/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index c969aef675ff9..5322d24e38934 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -55,12 +55,19 @@ impl Clone for DefPathTable {
 }
 
 impl DefPathTable {
+    pub fn new() -> Self {
+        DefPathTable {
+            index_to_key: [vec![], vec![]],
+            key_to_index: FxHashMap(),
+            def_path_hashes: [vec![], vec![]],
+        }
+    }
 
-    fn allocate(&mut self,
-                key: DefKey,
-                def_path_hash: DefPathHash,
-                address_space: DefIndexAddressSpace)
-                -> DefIndex {
+    pub fn allocate(&mut self,
+                    key: DefKey,
+                    def_path_hash: DefPathHash,
+                    address_space: DefIndexAddressSpace)
+                    -> DefIndex {
         let index = {
             let index_to_key = &mut self.index_to_key[address_space.index()];
             let index = DefIndex::new(index_to_key.len() + address_space.start());
@@ -241,7 +248,7 @@ pub struct DefKey {
 }
 
 impl DefKey {
-    fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
+    pub fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
         let mut hasher = StableHasher::new();
 
         // We hash a 0u8 here to disambiguate between regular DefPath hashes,
@@ -284,7 +291,7 @@ impl DefKey {
         DefPathHash(hasher.finish())
     }
 
-    fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> DefPathHash {
+    pub fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> DefPathHash {
         let mut hasher = StableHasher::new();
         // Disambiguate this from a regular DefPath hash,
         // see compute_stable_hash() above.
@@ -446,11 +453,7 @@ impl Definitions {
     /// Create new empty definition map.
     pub fn new() -> Definitions {
         Definitions {
-            table: DefPathTable {
-                index_to_key: [vec![], vec![]],
-                key_to_index: FxHashMap(),
-                def_path_hashes: [vec![], vec![]],
-            },
+            table: DefPathTable::new(),
             node_to_def_index: NodeMap(),
             def_index_to_node: [vec![], vec![]],
             node_to_hir_id: IndexVec::new(),
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e27990c29cf9e..e6dc5da969a88 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -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_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 2e949f48c175e..0b950787e3b91 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -13,7 +13,6 @@ 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_back = { path = "../librustc_back" }
 rustc_borrowck = { path = "../librustc_borrowck" }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 27c2d22168c8b..57a09ed15032f 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -26,7 +26,8 @@ use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
 use rustc::util::common::record_time;
 use rustc::util::nodemap::FxHashSet;
 use rustc::middle::cstore::NativeLibrary;
-use rustc::hir::map::Definitions;
+use rustc::hir::map::{Definitions, DefKey, DefPathData, DisambiguatedDefPathData, ITEM_LIKE_SPACE};
+use rustc::hir::map::definitions::DefPathTable;
 
 use std::cell::{RefCell, Cell};
 use std::ops::Deref;
@@ -34,7 +35,7 @@ use std::path::PathBuf;
 use std::rc::Rc;
 use std::{cmp, fs};
 
-use syntax::ast;
+use syntax::ast::{self, Ident};
 use syntax::abi::Abi;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
@@ -307,9 +308,16 @@ impl<'a> CrateLoader<'a> {
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
-        let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
-            crate_root.def_path_table.decode(&metadata)
+        let proc_macros = crate_root.macro_derive_registrar.map(|_| {
+            self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
         });
+        let def_path_table = if let Some(ref proc_macros) = proc_macros {
+            proc_macro_def_path_table(proc_macros)
+        } else {
+            record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
+                crate_root.def_path_table.decode(&metadata)
+            })
+        };
 
         let exported_symbols = crate_root.exported_symbols
                                          .map(|x| x.decode(&metadata).collect());
@@ -328,9 +336,7 @@ impl<'a> CrateLoader<'a> {
             def_path_table: Rc::new(def_path_table),
             exported_symbols: exported_symbols,
             trait_impls: trait_impls,
-            proc_macros: crate_root.macro_derive_registrar.map(|_| {
-                self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
-            }),
+            proc_macros: proc_macros,
             root: crate_root,
             blob: metadata,
             cnum_map: RefCell::new(cnum_map),
@@ -1213,3 +1219,31 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         }
     }
 }
+
+fn proc_macro_def_path_table(proc_macros: &[(ast::Name, Rc<SyntaxExtension>)]) -> DefPathTable {
+    let mut table = DefPathTable::new();
+    let root = DefKey {
+        parent: None,
+        disambiguated_data: DisambiguatedDefPathData {
+            data: DefPathData::CrateRoot,
+            disambiguator: 0,
+        },
+    };
+
+    let initial_hash = DefKey::root_parent_stable_hash("", "");
+    let root_hash = root.compute_stable_hash(initial_hash);
+    let root_id = table.allocate(root, root_hash, ITEM_LIKE_SPACE);
+    let root_path_hash = table.def_path_hash(root_id);
+    for proc_macro in proc_macros {
+        let key = DefKey {
+            parent: Some(CRATE_DEF_INDEX),
+            disambiguated_data: DisambiguatedDefPathData {
+                data: DefPathData::MacroDef(Ident::with_empty_ctxt(proc_macro.0)),
+                disambiguator: 0,
+            },
+        };
+        let def_path_hash = key.compute_stable_hash(root_path_hash);
+        table.allocate(key, def_path_hash, ITEM_LIKE_SPACE);
+    }
+    table
+}
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 0649553e382e3..ff5febadeb70f 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};
@@ -365,6 +366,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);
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 728ab30bb17dc..b974541ef255a 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 2a504c4c07794..63a24c7db18ff 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1095,6 +1095,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<_>>()),
@@ -1102,11 +1103,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/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 8bd58ec7a52d5..325a5cdf8fc02 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -100,7 +100,7 @@ impl Path {
         let name = self.segments[0].identifier.name;
         if !self.is_global() && name != "$crate" &&
            name != keywords::SelfValue.name() && name != keywords::Super.name() {
-            self.segments.insert(0, PathSegment::crate_root());
+            self.segments.insert(0, PathSegment::crate_root(self.span));
         }
         self
     }
@@ -134,10 +134,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/ext/base.rs b/src/libsyntax/ext/base.rs
index af5eabf06f87b..7a5c9456c5315 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -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,
         }
     }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index a4580ea3939fb..5168943d108cb 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -320,7 +320,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)));
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index d7d3a70f3c7c5..3f3c94536a6e7 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 {
@@ -1464,9 +1470,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()
@@ -1500,7 +1506,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 2032aecacbb91..ca4814397d8ac 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -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
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/parser.rs b/src/libsyntax/parse/parser.rs
index 25ab46f6f9e2b..a30dcef6f44e1 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1777,7 +1777,7 @@ impl<'a> Parser<'a> {
         };
 
         if is_global {
-            segments.insert(0, PathSegment::crate_root());
+            segments.insert(0, PathSegment::crate_root(lo));
         }
 
         // Assemble the result.
@@ -6187,7 +6187,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 f208b0f56f81e..e568af66e8aa8 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -349,6 +349,60 @@ impl Token {
             _ => false,
         }
     }
+
+    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,
+        })
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
@@ -398,3 +452,12 @@ 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,
+    }
+}
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index ab4f697071477..2637972cc6362 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>),
 }
 
@@ -196,6 +201,10 @@ impl TokenStream {
         }
     }
 
+    pub fn builder() -> TokenStreamBuilder {
+        TokenStreamBuilder(Vec::new())
+    }
+
     pub fn concat(mut streams: Vec<TokenStream>) -> TokenStream {
         match streams.len() {
             0 => TokenStream::empty(),
@@ -225,6 +234,99 @@ impl TokenStream {
         }
         true
     }
+
+    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 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 +336,7 @@ pub struct Cursor(CursorKind);
 enum CursorKind {
     Empty,
     Tree(TokenTree, bool /* consumed? */),
+    JointTree(TokenTree, bool /* consumed? */),
     Stream(StreamCursor),
 }
 
@@ -245,12 +348,13 @@ struct StreamCursor {
 }
 
 impl StreamCursor {
-    fn next(&mut self) -> Option<TokenTree> {
+    fn next_as_stream(&mut self) -> Option<TokenStream> {
         loop {
             if self.index < self.stream.len() {
                 self.index += 1;
-                match self.stream[self.index - 1].kind.clone() {
-                    TokenStreamKind::Tree(tree) => return Some(tree),
+                let next = self.stream[self.index - 1].clone();
+                match next.kind {
+                    TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => return Some(next),
                     TokenStreamKind::Stream(stream) => {
                         self.stack.push((mem::replace(&mut self.stream, stream),
                                          mem::replace(&mut self.index, 0)));
@@ -271,14 +375,10 @@ impl Iterator for Cursor {
     type Item = TokenTree;
 
     fn next(&mut self) -> Option<TokenTree> {
-        let (tree, consumed) = match self.0 {
-            CursorKind::Tree(ref tree, ref mut consumed @ false) => (tree, consumed),
-            CursorKind::Stream(ref mut cursor) => return cursor.next(),
-            _ => return None,
-        };
-
-        *consumed = true;
-        Some(tree.clone())
+        self.next_as_stream().map(|stream| match stream.kind {
+            TokenStreamKind::Tree(tree) | TokenStreamKind::JointTree(tree) => tree,
+            _ => unreachable!()
+        })
     }
 }
 
@@ -287,16 +387,32 @@ impl Cursor {
         Cursor(match stream.kind {
             TokenStreamKind::Empty => CursorKind::Empty,
             TokenStreamKind::Tree(tree) => CursorKind::Tree(tree, false),
+            TokenStreamKind::JointTree(tree) => CursorKind::JointTree(tree, false),
             TokenStreamKind::Stream(stream) => {
                 CursorKind::Stream(StreamCursor { stream: stream, index: 0, stack: Vec::new() })
             }
         })
     }
 
+    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 original_stream(self) -> TokenStream {
         match self.0 {
             CursorKind::Empty => TokenStream::empty(),
             CursorKind::Tree(tree, _) => tree.into(),
+            CursorKind::JointTree(tree, _) => tree.joint(),
             CursorKind::Stream(cursor) => TokenStream::concat_rc_slice({
                 cursor.stack.get(0).cloned().map(|(stream, _)| stream).unwrap_or(cursor.stream)
             }),
@@ -307,8 +423,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 +433,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 +469,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/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/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
index 0433b95865ef8..9406eda5231d5 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, proc_macro_lib)]
 
-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, TokenKind, 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 {
+            TokenKind::Sequence(_, 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 {
+            TokenKind::Word(word) => *word == *"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.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/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..d98c6932c51e1 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) && feature_name != "proc_macro" {
                         err("duplicating a lang feature");
                     }
                     if let Some(ref s) = lib_features.get(name) {

From 7d493bdd2a9f86ed51bc80a5c91cbb502aa3b3c4 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Wed, 29 Mar 2017 01:55:01 +0000
Subject: [PATCH 06/52] Add `LazyTokenStream`.

---
 src/libproc_macro/lib.rs                      | 36 ++++++++++---
 src/libsyntax/attr.rs                         |  4 +-
 src/libsyntax/ext/base.rs                     |  2 +-
 src/libsyntax/ext/expand.rs                   | 40 ++++----------
 src/libsyntax/ext/quote.rs                    | 36 ++++++-------
 src/libsyntax/ext/tt/transcribe.rs            |  2 +-
 src/libsyntax/fold.rs                         |  4 +-
 src/libsyntax/parse/attr.rs                   |  4 +-
 src/libsyntax/parse/parser.rs                 | 10 ++--
 src/libsyntax/parse/token.rs                  | 53 ++++++++++++++++---
 src/libsyntax/print/pprust.rs                 |  2 +-
 src/libsyntax/tokenstream.rs                  | 45 +++++++++++-----
 .../proc-macro/auxiliary/attr-args.rs         |  2 +-
 13 files changed, 151 insertions(+), 89 deletions(-)

diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index f1abd3339ed53..8a345e67c57b3 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -42,6 +42,7 @@
 #![feature(staged_api)]
 #![feature(lang_items)]
 
+#[macro_use]
 extern crate syntax;
 extern crate syntax_pos;
 
@@ -50,7 +51,8 @@ use std::str::FromStr;
 
 use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
-use syntax::parse::{self, token};
+use syntax::parse::{self, token, parse_stream_from_source_str};
+use syntax::print::pprust;
 use syntax::symbol;
 use syntax::tokenstream;
 use syntax_pos::DUMMY_SP;
@@ -337,8 +339,18 @@ impl Iterator for TokenIter {
     type Item = TokenTree;
 
     fn next(&mut self) -> Option<TokenTree> {
-        self.next.take().or_else(|| self.cursor.next_as_stream())
-            .map(|next| TokenTree::from_raw(next, &mut self.next))
+        loop {
+            let next =
+                unwrap_or!(self.next.take().or_else(|| self.cursor.next_as_stream()), return None);
+            let tree = TokenTree::from_raw(next, &mut self.next);
+            if tree.span.0 == DUMMY_SP {
+                if let TokenKind::Sequence(Delimiter::None, stream) = tree.kind {
+                    self.cursor.insert(stream.0);
+                    continue
+                }
+            }
+            return Some(tree);
+        }
     }
 }
 
@@ -449,7 +461,14 @@ impl TokenTree {
             Ident(ident) | Lifetime(ident) => TokenKind::Word(Symbol(ident.name)),
             Literal(..) | DocComment(..) => TokenKind::Literal(self::Literal(token)),
 
-            Interpolated(..) => unimplemented!(),
+            Interpolated(ref nt) => __internal::with_sess(|(sess, _)| {
+                TokenKind::Sequence(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!(),
@@ -530,20 +549,21 @@ pub mod __internal {
     pub use self::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::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 {
-        let (span, token) = (item.span, token::Interpolated(Rc::new(token::NtItem(item))));
-        TokenStream(tokenstream::TokenTree::Token(span, token).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 {
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 7a5c9456c5315..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));
                     }
                 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 11efef4549976..d2e51c9cb4868 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -21,15 +21,15 @@ 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));
@@ -769,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, item.span())
-}
-
-fn string_to_stream(text: String, parse_sess: &ParseSess, span: Span) -> TokenStream {
-    let filename = String::from("<macro expansion>");
-    filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text), Some(span))
-}
-
 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();
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 314a97496f8cc..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))]
         }
     }
 
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 9438e2fb0e5bf..fe3dd83f9d5c0 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -156,7 +156,7 @@ pub fn transcribe(cx: &ExtCtxt,
                             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()));
+                            let token = TokenTree::Token(sp, Token::interpolated((**nt).clone()));
                             result.push(token.into());
                         }
                     } else {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index ca4814397d8ac..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::*;
@@ -586,7 +586,7 @@ 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))
         }
         _ => 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/parser.rs b/src/libsyntax/parse/parser.rs
index a30dcef6f44e1..2858d49d63db7 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);
             }
@@ -1620,7 +1620,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); }
@@ -1791,7 +1791,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,
@@ -2635,7 +2635,7 @@ impl<'a> Parser<'a> {
             }
             token::Interpolated(ref nt) => {
                 self.meta_var_span = Some(self.span);
-                match **nt {
+                match nt.0 {
                     token::NtIdent(ident) => ident,
                     _ => return,
                 }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index e568af66e8aa8..189a18f442033 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -16,9 +16,11 @@ 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::cell::RefCell;
 use std::fmt;
 use std::rc::Rc;
 
@@ -168,7 +170,7 @@ pub enum Token {
     Lifetime(ast::Ident),
 
     /* For interpolation */
-    Interpolated(Rc<Nonterminal>),
+    Interpolated(Rc<(Nonterminal, LazyTokenStream)>),
     // Can be expanded into several tokens.
     /// Doc comment
     DocComment(ast::Name),
@@ -187,6 +189,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 {
@@ -211,7 +217,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,
             },
@@ -234,7 +240,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,
             },
@@ -253,7 +259,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,
             },
@@ -285,7 +291,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;
             }
         }
@@ -461,3 +467,38 @@ pub fn is_op(tok: &Token) -> bool {
         _ => true,
     }
 }
+
+#[derive(Clone, Eq, PartialEq, Debug)]
+pub struct LazyTokenStream(RefCell<Option<TokenStream>>);
+
+impl LazyTokenStream {
+    pub fn new() -> Self {
+        LazyTokenStream(RefCell::new(None))
+    }
+
+    pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream {
+        let mut opt_stream = self.0.borrow_mut();
+        if opt_stream.is_none() {
+            *opt_stream = Some(f());
+        };
+        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) {
+        self.0.borrow().hash(hasher);
+    }
+}
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6c6ca556e35ed..ac5b32c828ae2 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -275,7 +275,7 @@ pub fn token_to_string(tok: &Token) -> 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 2637972cc6362..a3c3fa3a52ee7 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -348,6 +348,10 @@ struct StreamCursor {
 }
 
 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 self.index < self.stream.len() {
@@ -355,10 +359,7 @@ impl StreamCursor {
                 let next = self.stream[self.index - 1].clone();
                 match next.kind {
                     TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => return Some(next),
-                    TokenStreamKind::Stream(stream) => {
-                        self.stack.push((mem::replace(&mut self.stream, stream),
-                                         mem::replace(&mut self.index, 0)));
-                    }
+                    TokenStreamKind::Stream(stream) => self.insert(stream),
                     TokenStreamKind::Empty => {}
                 }
             } else if let Some((stream, index)) = self.stack.pop() {
@@ -369,6 +370,11 @@ impl StreamCursor {
             }
         }
     }
+
+    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 {
@@ -388,9 +394,7 @@ impl Cursor {
             TokenStreamKind::Empty => CursorKind::Empty,
             TokenStreamKind::Tree(tree) => CursorKind::Tree(tree, false),
             TokenStreamKind::JointTree(tree) => CursorKind::JointTree(tree, false),
-            TokenStreamKind::Stream(stream) => {
-                CursorKind::Stream(StreamCursor { stream: stream, index: 0, stack: Vec::new() })
-            }
+            TokenStreamKind::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)),
         })
     }
 
@@ -408,13 +412,30 @@ impl Cursor {
         Some(stream)
     }
 
-    pub fn original_stream(self) -> TokenStream {
+    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::JointTree(tree, _) => tree.joint(),
-            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())
             }),
         }
     }
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!" }

From 20a90485c040df87a667e9b6ee38e4d8a7d7fc5d Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 31 Mar 2017 04:06:28 +0000
Subject: [PATCH 07/52] Add exmaple/test for `quote!` hygiene.

---
 .../proc-macro/auxiliary/hygiene_example.rs   | 19 ++++++++++
 .../auxiliary/hygiene_example_codegen.rs      | 36 +++++++++++++++++++
 .../proc-macro/hygiene_example.rs             | 27 ++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs

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-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);
+}

From 1e32a3f15e35075b537741cdfef40f29bb856582 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 31 Mar 2017 04:08:33 +0000
Subject: [PATCH 08/52] Test compound tokens.

---
 .../auxiliary/count_compound_ops.rs           | 36 +++++++++++++++++++
 .../proc-macro/count_compound_ops.rs          | 20 +++++++++++
 2 files changed, 56 insertions(+)
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs

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..2ff9dc2849460
--- /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, TokenKind, OpKind, Literal, quote};
+
+#[proc_macro]
+pub fn count_compound_ops(input: TokenStream) -> TokenStream {
+    assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3);
+    TokenKind::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 {
+            TokenKind::Op(c, OpKind::Alone) => count += 1,
+            TokenKind::Sequence(_, tokens) => count += count_compound_ops_helper(tokens),
+            _ => {}
+        }
+    }
+    count
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
new file mode 100644
index 0000000000000..1a2b144e4717b
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
@@ -0,0 +1,20 @@
+// 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:count_compound_ops.rs
+
+#![feature(proc_macro)]
+
+extern crate count_compound_ops;
+use count_compound_ops::count_compound_ops;
+
+fn main() {
+    assert_eq!(count_compound_ops!(foo<=>bar <<<! -baz ++), 4);
+}

From 71d4a860a1797300f976b45d7b7a41815eca6207 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Mon, 5 Jun 2017 01:41:33 +0000
Subject: [PATCH 09/52] Address review comments.

---
 src/libproc_macro/lib.rs                      | 190 +++++++++++-------
 src/libproc_macro/quote.rs                    |  16 +-
 src/librustc_metadata/creader.rs              |   6 +-
 src/libsyntax/parse/lexer/mod.rs              |   2 +-
 src/libsyntax/parse/token.rs                  |  44 ++--
 src/libsyntax/tokenstream.rs                  |  10 +-
 .../auxiliary/cond_plugin.rs                  |   6 +-
 .../auxiliary/count_compound_ops.rs           |   8 +-
 8 files changed, 172 insertions(+), 110 deletions(-)

diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 8a345e67c57b3..06f9634d70613 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -46,14 +46,14 @@
 extern crate syntax;
 extern crate syntax_pos;
 
-use std::{fmt, iter, ops};
+use std::{ascii, fmt, iter};
 use std::str::FromStr;
 
 use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
 use syntax::parse::{self, token, parse_stream_from_source_str};
 use syntax::print::pprust;
-use syntax::symbol;
+use syntax::symbol::Symbol;
 use syntax::tokenstream;
 use syntax_pos::DUMMY_SP;
 use syntax_pos::SyntaxContext;
@@ -68,12 +68,12 @@ use syntax_pos::SyntaxContext;
 /// 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")]
-#[derive(Clone)]
+#[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: (),
 }
@@ -110,16 +110,20 @@ impl fmt::Display for TokenStream {
 #[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_raw())
+        TokenStream(tree.to_internal())
     }
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl From<TokenKind> for TokenStream {
-    fn from(kind: TokenKind) -> TokenStream {
+impl From<TokenNode> for TokenStream {
+    fn from(kind: TokenNode) -> TokenStream {
         TokenTree::from(kind).into()
     }
 }
@@ -127,7 +131,7 @@ impl From<TokenKind> for TokenStream {
 #[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::TokenStream::builder();
+        let mut builder = tokenstream::TokenStreamBuilder::new();
         for stream in streams {
             builder.push(stream.into().0);
         }
@@ -138,10 +142,10 @@ impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl IntoIterator for TokenStream {
     type Item = TokenTree;
-    type IntoIter = TokenIter;
+    type IntoIter = TokenTreeIter;
 
-    fn into_iter(self) -> TokenIter {
-        TokenIter { cursor: self.0.trees(), next: None }
+    fn into_iter(self) -> TokenTreeIter {
+        TokenTreeIter { cursor: self.0.trees(), next: None }
     }
 }
 
@@ -161,7 +165,7 @@ impl TokenStream {
 
 /// A region of source code, along with macro expansion information.
 #[unstable(feature = "proc_macro", issue = "38356")]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct Span(syntax_pos::Span);
 
 #[unstable(feature = "proc_macro", issue = "38356")]
@@ -174,6 +178,13 @@ impl Default for Span {
     }
 }
 
+/// 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")]
@@ -184,17 +195,17 @@ impl Span {
 
 /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
 #[unstable(feature = "proc_macro", issue = "38356")]
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct TokenTree {
     /// The `TokenTree`'s span
     pub span: Span,
     /// Description of the `TokenTree`
-    pub kind: TokenKind,
+    pub kind: TokenNode,
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl From<TokenKind> for TokenTree {
-    fn from(kind: TokenKind) -> TokenTree {
+impl From<TokenNode> for TokenTree {
+    fn from(kind: TokenNode) -> TokenTree {
         TokenTree { span: Span::default(), kind: kind }
     }
 }
@@ -207,21 +218,21 @@ impl fmt::Display for TokenTree {
 }
 
 /// Description of a `TokenTree`
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
-pub enum TokenKind {
+pub enum TokenNode {
     /// A delimited tokenstream.
-    Sequence(Delimiter, TokenStream),
+    Group(Delimiter, TokenStream),
     /// A unicode identifier.
-    Word(Symbol),
+    Term(Term),
     /// A punctuation character (`+`, `,`, `$`, etc.).
-    Op(char, OpKind),
+    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)]
+#[derive(Copy, Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
 pub enum Delimiter {
     /// `( ... )`
@@ -235,30 +246,28 @@ pub enum Delimiter {
 }
 
 /// An interned string.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
-pub struct Symbol(symbol::Symbol);
+pub struct Term(Symbol);
 
-#[unstable(feature = "proc_macro", issue = "38356")]
-impl<'a> From<&'a str> for Symbol {
-    fn from(string: &'a str) -> Symbol {
-        Symbol(symbol::Symbol::intern(string))
+impl Term {
+    /// Intern a string into a `Term`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn intern(string: &str) -> Term {
+        Term(Symbol::intern(string))
     }
-}
 
-#[unstable(feature = "proc_macro", issue = "38356")]
-impl ops::Deref for Symbol {
-    type Target = str;
-
-    fn deref(&self) -> &str {
-        unsafe { &*(self.0.as_str().deref() as *const str) }
+    /// 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)]
+#[derive(Copy, Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
-pub enum OpKind {
+pub enum Spacing {
     /// e.g. `+` is `Alone` in `+ =`.
     Alone,
     /// e.g. `+` is `Joint` in `+=`.
@@ -266,14 +275,14 @@ pub enum OpKind {
 }
 
 /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
-#[derive(Clone)]
+#[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: TokenKind::Literal(self.clone()), span: Span(DUMMY_SP) }.fmt(f)
+        TokenTree { kind: TokenNode::Literal(self.clone()), span: Span(DUMMY_SP) }.fmt(f)
     }
 }
 
@@ -282,30 +291,51 @@ macro_rules! int_literals {
         /// Integer literal.
         #[unstable(feature = "proc_macro", issue = "38356")]
         pub fn $int_kind(n: $int_kind) -> Literal {
-            Literal::integer(n as i128, stringify!($int_kind))
+            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 integer(n: i128, kind: &'static str) -> Literal {
-        Literal(token::Literal(token::Lit::Integer(symbol::Symbol::intern(&n.to_string())),
-                               Some(symbol::Symbol::intern(kind))))
+    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 {
-        Literal(token::Literal(token::Lit::Float(symbol::Symbol::intern(&n.to_string())),
-                               Some(symbol::Symbol::intern("f32"))))
+        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: f32) -> Literal {
-        Literal(token::Literal(token::Lit::Float(symbol::Symbol::intern(&n.to_string())),
-                               Some(symbol::Symbol::intern("f64"))))
+    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.
@@ -315,7 +345,7 @@ impl Literal {
         for ch in string.chars() {
             escaped.extend(ch.escape_unicode());
         }
-        Literal(token::Literal(token::Lit::Str_(symbol::Symbol::intern(&escaped)), None))
+        Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None))
     }
 
     /// Character literal.
@@ -323,28 +353,36 @@ impl Literal {
     pub fn character(ch: char) -> Literal {
         let mut escaped = String::new();
         escaped.extend(ch.escape_unicode());
-        Literal(token::Literal(token::Lit::Char(symbol::Symbol::intern(&escaped)), None))
+        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 TokenIter {
+pub struct TokenTreeIter {
     cursor: tokenstream::Cursor,
     next: Option<tokenstream::TokenStream>,
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl Iterator for TokenIter {
+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_raw(next, &mut self.next);
+            let tree = TokenTree::from_internal(next, &mut self.next);
             if tree.span.0 == DUMMY_SP {
-                if let TokenKind::Sequence(Delimiter::None, stream) = tree.kind {
+                if let TokenNode::Group(Delimiter::None, stream) = tree.kind {
                     self.cursor.insert(stream.0);
                     continue
                 }
@@ -355,7 +393,7 @@ impl Iterator for TokenIter {
 }
 
 impl Delimiter {
-    fn from_raw(delim: token::DelimToken) -> Delimiter {
+    fn from_internal(delim: token::DelimToken) -> Delimiter {
         match delim {
             token::Paren => Delimiter::Parenthesis,
             token::Brace => Delimiter::Brace,
@@ -364,7 +402,7 @@ impl Delimiter {
         }
     }
 
-    fn to_raw(self) -> token::DelimToken {
+    fn to_internal(self) -> token::DelimToken {
         match self {
             Delimiter::Parenthesis => token::Paren,
             Delimiter::Brace => token::Brace,
@@ -375,7 +413,7 @@ impl Delimiter {
 }
 
 impl TokenTree {
-    fn from_raw(stream: tokenstream::TokenStream, next: &mut Option<tokenstream::TokenStream>)
+    fn from_internal(stream: tokenstream::TokenStream, next: &mut Option<tokenstream::TokenStream>)
                 -> TokenTree {
         use syntax::parse::token::*;
 
@@ -383,17 +421,17 @@ impl TokenTree {
         let (mut span, token) = match tree {
             tokenstream::TokenTree::Token(span, token) => (span, token),
             tokenstream::TokenTree::Delimited(span, delimed) => {
-                let delimiter = Delimiter::from_raw(delimed.delim);
+                let delimiter = Delimiter::from_internal(delimed.delim);
                 return TokenTree {
                     span: Span(span),
-                    kind: TokenKind::Sequence(delimiter, TokenStream(delimed.tts.into())),
+                    kind: TokenNode::Group(delimiter, TokenStream(delimed.tts.into())),
                 };
             }
         };
 
-        let op_kind = if is_joint { OpKind::Joint } else { OpKind::Alone };
+        let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone };
         macro_rules! op {
-            ($op:expr) => { TokenKind::Op($op, op_kind) }
+            ($op:expr) => { TokenNode::Op($op, op_kind) }
         }
 
         macro_rules! joint {
@@ -402,12 +440,12 @@ impl TokenTree {
 
         fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span,
                  next: &mut Option<tokenstream::TokenStream>)
-                 -> TokenKind {
+                 -> 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() });
-            TokenKind::Op(first, OpKind::Joint)
+            TokenNode::Op(first, Spacing::Joint)
         }
 
         let kind = match token {
@@ -458,11 +496,11 @@ impl TokenTree {
             Question => op!('?'),
             Underscore => op!('_'),
 
-            Ident(ident) | Lifetime(ident) => TokenKind::Word(Symbol(ident.name)),
-            Literal(..) | DocComment(..) => TokenKind::Literal(self::Literal(token)),
+            Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)),
+            Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)),
 
             Interpolated(ref nt) => __internal::with_sess(|(sess, _)| {
-                TokenKind::Sequence(Delimiter::None, TokenStream(nt.1.force(|| {
+                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);
@@ -477,25 +515,25 @@ impl TokenTree {
         TokenTree { span: Span(span), kind: kind }
     }
 
-    fn to_raw(self) -> tokenstream::TokenStream {
+    fn to_internal(self) -> tokenstream::TokenStream {
         use syntax::parse::token::*;
         use syntax::tokenstream::{TokenTree, Delimited};
 
         let (op, kind) = match self.kind {
-            TokenKind::Op(op, kind) => (op, kind),
-            TokenKind::Sequence(delimiter, tokens) => {
+            TokenNode::Op(op, kind) => (op, kind),
+            TokenNode::Group(delimiter, tokens) => {
                 return TokenTree::Delimited(self.span.0, Delimited {
-                    delim: delimiter.to_raw(),
+                    delim: delimiter.to_internal(),
                     tts: tokens.0.into(),
                 }).into();
             },
-            TokenKind::Word(symbol) => {
+            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();
             }
-            TokenKind::Literal(token) => return TokenTree::Token(self.span.0, token.0).into(),
+            TokenNode::Literal(token) => return TokenTree::Token(self.span.0, token.0).into(),
         };
 
         let token = match op {
@@ -526,8 +564,8 @@ impl TokenTree {
 
         let tree = TokenTree::Token(self.span.0, token);
         match kind {
-            OpKind::Alone => tree.into(),
-            OpKind::Joint => tree.joint(),
+            Spacing::Alone => tree.into(),
+            Spacing::Joint => tree.joint(),
         }
     }
 }
@@ -543,10 +581,8 @@ impl TokenTree {
 /// all of the contents.
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
-#[path = ""]
 pub mod __internal {
-    mod quote;
-    pub use self::quote::{Quoter, __rt};
+    pub use quote::{Quoter, __rt};
 
     use std::cell::Cell;
 
diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs
index a3ea3925fcd48..bee2c1e0eb6b6 100644
--- a/src/libproc_macro/quote.rs
+++ b/src/libproc_macro/quote.rs
@@ -9,13 +9,17 @@
 // except according to those terms.
 
 //! # Quasiquoter
-//! This file contains the implementation internals of the quasiquoter provided by `qquote!`.
+//! 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};
+use syntax::tokenstream::{Delimited, TokenTree, TokenStream, TokenStreamBuilder};
 use syntax_pos::{DUMMY_SP, Span};
 use syntax_pos::hygiene::SyntaxContext;
 
@@ -25,7 +29,7 @@ pub mod __rt {
     pub use syntax::ast::Ident;
     pub use syntax::parse::token;
     pub use syntax::symbol::Symbol;
-    pub use syntax::tokenstream::{TokenStream, TokenTree, Delimited};
+    pub use syntax::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree, Delimited};
     pub use super::{ctxt, span};
 
     pub fn unquote<T: Into<::TokenStream> + Clone>(tokens: &T) -> TokenStream {
@@ -41,7 +45,7 @@ pub fn span() -> Span {
     ::Span::default().0
 }
 
-trait Quote {
+pub trait Quote {
     fn quote(&self) -> TokenStream;
 }
 
@@ -98,8 +102,8 @@ impl<T: Quote> Quote for Option<T> {
 
 impl Quote for TokenStream {
     fn quote(&self) -> TokenStream {
-        let mut builder = TokenStream::builder();
-        builder.push(quote!(rt::TokenStream::builder()));
+        let mut builder = TokenStreamBuilder::new();
+        builder.push(quote!(rt::TokenStreamBuilder::new()));
 
         let mut trees = self.trees();
         loop {
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 57a09ed15032f..e008a5cd9ea61 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -14,7 +14,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob};
 use locator::{self, CratePaths};
 use schema::{CrateRoot, Tracked};
 
-use rustc::hir::def_id::{CrateNum, DefIndex};
+use rustc::hir::def_id::{CrateNum, DefIndex, CRATE_DEF_INDEX};
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::DepKind;
 use rustc::session::Session;
@@ -35,7 +35,7 @@ use std::path::PathBuf;
 use std::rc::Rc;
 use std::{cmp, fs};
 
-use syntax::ast::{self, Ident};
+use syntax::ast;
 use syntax::abi::Abi;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
@@ -1238,7 +1238,7 @@ fn proc_macro_def_path_table(proc_macros: &[(ast::Name, Rc<SyntaxExtension>)]) -
         let key = DefKey {
             parent: Some(CRATE_DEF_INDEX),
             disambiguated_data: DisambiguatedDefPathData {
-                data: DefPathData::MacroDef(Ident::with_empty_ctxt(proc_macro.0)),
+                data: DefPathData::MacroDef(proc_macro.0),
                 disambiguator: 0,
             },
         };
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index afc1e583d69bb..66775d8c43d63 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -483,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 \
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 189a18f442033..d4198261d3f69 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -20,8 +20,8 @@ use serialize::{Decodable, Decoder, Encodable, Encoder};
 use symbol::keywords;
 use tokenstream::{TokenStream, TokenTree};
 
-use std::cell::RefCell;
-use std::fmt;
+use std::cell::Cell;
+use std::{cmp, fmt};
 use std::rc::Rc;
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -169,7 +169,8 @@ pub enum Token {
     Underscore,
     Lifetime(ast::Ident),
 
-    /* For interpolation */
+    // 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
@@ -468,19 +469,40 @@ pub fn is_op(tok: &Token) -> bool {
     }
 }
 
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub struct LazyTokenStream(RefCell<Option<TokenStream>>);
+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(RefCell::new(None))
+        LazyTokenStream(Cell::new(None))
     }
 
     pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream {
-        let mut opt_stream = self.0.borrow_mut();
+        let mut opt_stream = self.0.take();
         if opt_stream.is_none() {
-            *opt_stream = Some(f());
-        };
+            opt_stream = Some(f());
+        }
+        self.0.set(opt_stream.clone());
         opt_stream.clone().unwrap()
     }
 }
@@ -498,7 +520,5 @@ impl Decodable for LazyTokenStream {
 }
 
 impl ::std::hash::Hash for LazyTokenStream {
-    fn hash<H: ::std::hash::Hasher>(&self, hasher: &mut H) {
-        self.0.borrow().hash(hasher);
-    }
+    fn hash<H: ::std::hash::Hasher>(&self, _hasher: &mut H) {}
 }
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index a3c3fa3a52ee7..8eee25405df6b 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -201,10 +201,6 @@ impl TokenStream {
         }
     }
 
-    pub fn builder() -> TokenStreamBuilder {
-        TokenStreamBuilder(Vec::new())
-    }
-
     pub fn concat(mut streams: Vec<TokenStream>) -> TokenStream {
         match streams.len() {
             0 => TokenStream::empty(),
@@ -235,6 +231,8 @@ 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),
@@ -277,6 +275,10 @@ impl TokenStream {
 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);
diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
index 9406eda5231d5..6d6a452b03b62 100644
--- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
@@ -15,7 +15,7 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenKind, quote};
+use proc_macro::{TokenStream, TokenNode, quote};
 
 #[proc_macro]
 pub fn cond(input: TokenStream) -> TokenStream {
@@ -23,7 +23,7 @@ pub fn cond(input: TokenStream) -> TokenStream {
     let mut input = input.into_iter().peekable();
     while let Some(tree) = input.next() {
         let cond = match tree.kind {
-            TokenKind::Sequence(_, cond) => cond,
+            TokenNode::Sequence(_, cond) => cond,
             _ => panic!("Invalid input"),
         };
         let mut cond_trees = cond.clone().into_iter();
@@ -33,7 +33,7 @@ pub fn cond(input: TokenStream) -> TokenStream {
             panic!("Invalid macro usage in cond: {}", cond);
         }
         let is_else = match test.kind {
-            TokenKind::Word(word) => *word == *"else",
+            TokenNode::Word(word) => word.as_str() == "else",
             _ => false,
         };
         conds.push(if is_else || input.peek().is_none() {
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
index 2ff9dc2849460..e7a0283962d81 100644
--- 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
@@ -15,20 +15,20 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenKind, OpKind, Literal, quote};
+use proc_macro::{TokenStream, TokenNode, OpKind, Literal, quote};
 
 #[proc_macro]
 pub fn count_compound_ops(input: TokenStream) -> TokenStream {
     assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3);
-    TokenKind::Literal(Literal::u32(count_compound_ops_helper(input))).into()
+    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 {
-            TokenKind::Op(c, OpKind::Alone) => count += 1,
-            TokenKind::Sequence(_, tokens) => count += count_compound_ops_helper(tokens),
+            TokenNode::Op(c, OpKind::Alone) => count += 1,
+            TokenNode::Sequence(_, tokens) => count += count_compound_ops_helper(tokens),
             _ => {}
         }
     }

From 699078a35be3ec30dfbb88683129a9f2fd4ad415 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 21 Jun 2017 11:32:32 -0700
Subject: [PATCH 10/52] Fix a semantic merge conflict

---
 src/tools/tidy/src/features.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index d98c6932c51e1..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) && feature_name != "proc_macro" {
+                    if lang_features.contains_key(name) && name != "proc_macro" {
                         err("duplicating a lang feature");
                     }
                     if let Some(ref s) = lib_features.get(name) {

From 4012b8dc4abb4915b3804a88c8e5c6d5de91d410 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 21 Jun 2017 11:32:50 -0700
Subject: [PATCH 11/52] Update UI test with proc_macro changes

---
 src/test/ui/token/macro-incomplete-parse.stderr | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr
index 14a7186aab19c..054364b0048f6 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

From 302935ff2a169d57cdde78f17591e13e8aa47f9e Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 21 Jun 2017 11:34:33 -0700
Subject: [PATCH 12/52] Revert a few changes

---
 src/librustc/hir/map/definitions.rs | 27 ++++++++--------
 src/librustc_metadata/creader.rs    | 48 +++++------------------------
 2 files changed, 19 insertions(+), 56 deletions(-)

diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 5322d24e38934..c969aef675ff9 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -55,19 +55,12 @@ impl Clone for DefPathTable {
 }
 
 impl DefPathTable {
-    pub fn new() -> Self {
-        DefPathTable {
-            index_to_key: [vec![], vec![]],
-            key_to_index: FxHashMap(),
-            def_path_hashes: [vec![], vec![]],
-        }
-    }
 
-    pub fn allocate(&mut self,
-                    key: DefKey,
-                    def_path_hash: DefPathHash,
-                    address_space: DefIndexAddressSpace)
-                    -> DefIndex {
+    fn allocate(&mut self,
+                key: DefKey,
+                def_path_hash: DefPathHash,
+                address_space: DefIndexAddressSpace)
+                -> DefIndex {
         let index = {
             let index_to_key = &mut self.index_to_key[address_space.index()];
             let index = DefIndex::new(index_to_key.len() + address_space.start());
@@ -248,7 +241,7 @@ pub struct DefKey {
 }
 
 impl DefKey {
-    pub fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
+    fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
         let mut hasher = StableHasher::new();
 
         // We hash a 0u8 here to disambiguate between regular DefPath hashes,
@@ -291,7 +284,7 @@ impl DefKey {
         DefPathHash(hasher.finish())
     }
 
-    pub fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> DefPathHash {
+    fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> DefPathHash {
         let mut hasher = StableHasher::new();
         // Disambiguate this from a regular DefPath hash,
         // see compute_stable_hash() above.
@@ -453,7 +446,11 @@ impl Definitions {
     /// Create new empty definition map.
     pub fn new() -> Definitions {
         Definitions {
-            table: DefPathTable::new(),
+            table: DefPathTable {
+                index_to_key: [vec![], vec![]],
+                key_to_index: FxHashMap(),
+                def_path_hashes: [vec![], vec![]],
+            },
             node_to_def_index: NodeMap(),
             def_index_to_node: [vec![], vec![]],
             node_to_hir_id: IndexVec::new(),
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index e008a5cd9ea61..27c2d22168c8b 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -14,7 +14,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob};
 use locator::{self, CratePaths};
 use schema::{CrateRoot, Tracked};
 
-use rustc::hir::def_id::{CrateNum, DefIndex, CRATE_DEF_INDEX};
+use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::DepKind;
 use rustc::session::Session;
@@ -26,8 +26,7 @@ use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
 use rustc::util::common::record_time;
 use rustc::util::nodemap::FxHashSet;
 use rustc::middle::cstore::NativeLibrary;
-use rustc::hir::map::{Definitions, DefKey, DefPathData, DisambiguatedDefPathData, ITEM_LIKE_SPACE};
-use rustc::hir::map::definitions::DefPathTable;
+use rustc::hir::map::Definitions;
 
 use std::cell::{RefCell, Cell};
 use std::ops::Deref;
@@ -308,16 +307,9 @@ impl<'a> CrateLoader<'a> {
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
-        let proc_macros = crate_root.macro_derive_registrar.map(|_| {
-            self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
+        let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
+            crate_root.def_path_table.decode(&metadata)
         });
-        let def_path_table = if let Some(ref proc_macros) = proc_macros {
-            proc_macro_def_path_table(proc_macros)
-        } else {
-            record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
-                crate_root.def_path_table.decode(&metadata)
-            })
-        };
 
         let exported_symbols = crate_root.exported_symbols
                                          .map(|x| x.decode(&metadata).collect());
@@ -336,7 +328,9 @@ impl<'a> CrateLoader<'a> {
             def_path_table: Rc::new(def_path_table),
             exported_symbols: exported_symbols,
             trait_impls: trait_impls,
-            proc_macros: proc_macros,
+            proc_macros: crate_root.macro_derive_registrar.map(|_| {
+                self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
+            }),
             root: crate_root,
             blob: metadata,
             cnum_map: RefCell::new(cnum_map),
@@ -1219,31 +1213,3 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         }
     }
 }
-
-fn proc_macro_def_path_table(proc_macros: &[(ast::Name, Rc<SyntaxExtension>)]) -> DefPathTable {
-    let mut table = DefPathTable::new();
-    let root = DefKey {
-        parent: None,
-        disambiguated_data: DisambiguatedDefPathData {
-            data: DefPathData::CrateRoot,
-            disambiguator: 0,
-        },
-    };
-
-    let initial_hash = DefKey::root_parent_stable_hash("", "");
-    let root_hash = root.compute_stable_hash(initial_hash);
-    let root_id = table.allocate(root, root_hash, ITEM_LIKE_SPACE);
-    let root_path_hash = table.def_path_hash(root_id);
-    for proc_macro in proc_macros {
-        let key = DefKey {
-            parent: Some(CRATE_DEF_INDEX),
-            disambiguated_data: DisambiguatedDefPathData {
-                data: DefPathData::MacroDef(proc_macro.0),
-                disambiguator: 0,
-            },
-        };
-        let def_path_hash = key.compute_stable_hash(root_path_hash);
-        table.allocate(key, def_path_hash, ITEM_LIKE_SPACE);
-    }
-    table
-}

From d316874c87e25669895c306658e15aa3746d66ab Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 21 Jun 2017 12:42:44 -0700
Subject: [PATCH 13/52] Update and fix a few tests

---
 src/libsyntax/parse/mod.rs                                  | 2 +-
 src/libsyntax/util/parser_testing.rs                        | 2 +-
 src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs         | 6 +++---
 .../proc-macro/auxiliary/count_compound_ops.rs              | 6 +++---
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index f917eec2cd0b1..bd9a621c00c00 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -687,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/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/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
index 6d6a452b03b62..e2c68a626f91e 100644
--- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
@@ -11,7 +11,7 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro)]
 
 extern crate proc_macro;
 
@@ -23,7 +23,7 @@ pub fn cond(input: TokenStream) -> TokenStream {
     let mut input = input.into_iter().peekable();
     while let Some(tree) = input.next() {
         let cond = match tree.kind {
-            TokenNode::Sequence(_, cond) => cond,
+            TokenNode::Group(_, cond) => cond,
             _ => panic!("Invalid input"),
         };
         let mut cond_trees = cond.clone().into_iter();
@@ -33,7 +33,7 @@ pub fn cond(input: TokenStream) -> TokenStream {
             panic!("Invalid macro usage in cond: {}", cond);
         }
         let is_else = match test.kind {
-            TokenNode::Word(word) => word.as_str() == "else",
+            TokenNode::Term(word) => word.as_str() == "else",
             _ => false,
         };
         conds.push(if is_else || input.peek().is_none() {
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
index e7a0283962d81..ec2ff0d1e2b8c 100644
--- 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
@@ -15,7 +15,7 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenNode, OpKind, Literal, quote};
+use proc_macro::{TokenStream, TokenNode, Spacing, Literal, quote};
 
 #[proc_macro]
 pub fn count_compound_ops(input: TokenStream) -> TokenStream {
@@ -27,8 +27,8 @@ fn count_compound_ops_helper(input: TokenStream) -> u32 {
     let mut count = 0;
     for token in input {
         match token.kind {
-            TokenNode::Op(c, OpKind::Alone) => count += 1,
-            TokenNode::Sequence(_, tokens) => count += count_compound_ops_helper(tokens),
+            TokenNode::Op(c, Spacing::Alone) => count += 1,
+            TokenNode::Group(_, tokens) => count += count_compound_ops_helper(tokens),
             _ => {}
         }
     }

From 7327cf7be59adbb57cbb246d50709306488a1167 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Thu, 29 Jun 2017 22:10:24 +0200
Subject: [PATCH 14/52] Toggle wrappers are now generated correctly

---
 src/librustdoc/html/static/main.js | 49 +++++++++++++++++-------------
 1 file changed, 28 insertions(+), 21 deletions(-)

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]);
         });
     });

From 8ee6bddf0b8b9b77ecd1e4b8105dc3fe161e6626 Mon Sep 17 00:00:00 2001
From: Ian Douglas Scott <ian@iandouglasscott.com>
Date: Thu, 29 Jun 2017 17:22:36 -0700
Subject: [PATCH 15/52] redox: symlink and readlink

---
 src/libstd/sys/redox/fs.rs           | 14 ++++++++++----
 src/libstd/sys/redox/syscall/flag.rs |  2 ++
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs
index 48d9cdcb2c937..9a16fc1bf66a9 100644
--- a/src/libstd/sys/redox/fs.rs
+++ b/src/libstd/sys/redox/fs.rs
@@ -420,12 +420,18 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    canonicalize(p)
+    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<()> {
-    ::sys_common::util::dumb_print(format_args!("Symlink\n"));
-    unimplemented!();
+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;

From aff84eb3aa24119084079d5aa2d385bfaa5c8a2d Mon Sep 17 00:00:00 2001
From: Stepan Koltsov <stepan.koltsov@gmail.com>
Date: Fri, 30 Jun 2017 23:13:40 +0300
Subject: [PATCH 16/52] Add .editorconfig to src/rustllvm

... which uses 2 space indent instead of common 4 spaces.
---
 src/rustllvm/.editorconfig | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 src/rustllvm/.editorconfig

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

From affe6e148c9aee2977d4ba0679f0ff92c67a16da Mon Sep 17 00:00:00 2001
From: Stepan Koltsov <stepan.koltsov@gmail.com>
Date: Fri, 30 Jun 2017 23:18:47 +0300
Subject: [PATCH 17/52] Ignore *.iml files

... which are IntelliJ IDEA module files. (`.idea` is IDEA project files.)
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

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

From 3456608aaed5db6ec3a520a295983e97c4f031fd Mon Sep 17 00:00:00 2001
From: Ian Douglas Scott <ian@iandouglasscott.com>
Date: Fri, 30 Jun 2017 13:37:05 -0700
Subject: [PATCH 18/52] Fix long line

---
 src/libstd/sys/redox/fs.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs
index 9a16fc1bf66a9..c5a19e8debe93 100644
--- a/src/libstd/sys/redox/fs.rs
+++ b/src/libstd/sys/redox/fs.rs
@@ -428,7 +428,8 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> {
 }
 
 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))?;
+    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(())

From a6994d7f3aed68f6a200fa6c48484924c4109c0b Mon Sep 17 00:00:00 2001
From: Behnam Esfahbod <behnam@zwnj.org>
Date: Fri, 30 Jun 2017 17:25:28 -0600
Subject: [PATCH 19/52] [libstd_unicode] Upgrade to Unicode 10.0.0

---
 src/libstd_unicode/tables.rs | 323 ++++++++++++++++++-----------------
 1 file changed, 168 insertions(+), 155 deletions(-)

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
         ],
     };
 

From dcd332ed94fb3dd6bf2f5789c8dd42f509337992 Mon Sep 17 00:00:00 2001
From: Scott McMurray <scottmcm@users.noreply.github.com>
Date: Sat, 1 Jul 2017 19:18:02 -0700
Subject: [PATCH 20/52] Delete deprecated & unstable range-specific `step_by`

Replacement: 41439
Deprecation: 42310 for 1.19
Fixes 41477
---
 src/liballoc/tests/vec_deque.rs               |   3 +-
 src/libcore/iter/mod.rs                       |   6 -
 src/libcore/iter/range.rs                     | 213 ------------------
 src/libcore/tests/iter.rs                     |  42 ++--
 src/libcore/tests/lib.rs                      |   1 -
 src/librand/lib.rs                            |   2 +-
 src/test/run-pass/range_inclusive.rs          |   2 +-
 .../sync-send-iterators-in-libcore.rs         |   2 +-
 8 files changed, 20 insertions(+), 251 deletions(-)

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/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 337f8aa31dc46..3b86e8e974441 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -36,7 +36,6 @@
 #![feature(sort_internals)]
 #![feature(sort_unstable)]
 #![feature(specialization)]
-#![feature(step_by)]
 #![feature(step_trait)]
 #![feature(test)]
 #![feature(trusted_len)]
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/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/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};

From d1316b468f969db58ccfc907f8b404d999b6e391 Mon Sep 17 00:00:00 2001
From: Ryan Thomas <ryan@ryant.org>
Date: Thu, 22 Jun 2017 20:49:22 +0100
Subject: [PATCH 21/52] Add docs for Debug* structs. #29355

This adds docs for the Debug* structs as well as examples from the
Formatter::debug_* methods, so that a user knows how to construct them.

I added these examples as the builders module is not public and hence
the debug_*_new() functions are not available to a user.

r? @steveklabnik

Review comments.

Mainly adding in the links for all of the structs and functions.

Remove rust tag on code blocks.
---
 src/libcore/fmt/builders.rs | 139 +++++++++++++++++++++++++++++++++---
 1 file changed, 129 insertions(+), 10 deletions(-)

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")]

From 3146e552d199a4db223773e0b80ce8cd510df78a Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizc@gmail.com>
Date: Tue, 30 May 2017 00:13:09 +0300
Subject: [PATCH 22/52] use PAGER to view --explain output #32665

---
 src/librustc_driver/lib.rs | 46 +++++++++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f2aacbc629fad..f408316c9f923 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -84,10 +84,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};
@@ -354,6 +355,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,13 +364,17 @@ 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)]);
+                    text.push('\n');
                 } else if is_in_code_block && dedented_line.starts_with("# ") {
                     continue;
                 } else {
-                    println!("{}", line);
+                    text.push_str(line);
+                    text.push('\n');
                 }
             }
+
+            show_content_with_pager(&text);
         }
         None => {
             early_error(output, &format!("no extended information for {}", code));
@@ -375,6 +382,39 @@ fn handle_explain(code: &str,
     }
 }
 
+fn show_content_with_pager(content: &String) {
+    let pager_name = env::var_os("PAGER").unwrap_or(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 {
+        println!("{}", content);
+    }
+}
+
 impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
     fn early_callback(&mut self,
                       matches: &getopts::Matches,

From 1beeb5a277ee18a8817b85d31595c7980fdf3627 Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizc@gmail.com>
Date: Thu, 29 Jun 2017 10:40:51 +0300
Subject: [PATCH 23/52] do not append an extra newline char

---
 src/librustc_driver/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f408316c9f923..58dd21c929248 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -411,7 +411,7 @@ fn show_content_with_pager(content: &String) {
     // If pager fails for whatever reason, we should still print the content
     // to standard output
     if fallback_to_println {
-        println!("{}", content);
+        print!("{}", content);
     }
 }
 

From 08b6bebbad39874a71f37dfb4c607544b6c943e9 Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizc@gmail.com>
Date: Thu, 29 Jun 2017 17:57:54 +0300
Subject: [PATCH 24/52] use unwrap_or_else to prevent unnecessary alloc

---
 src/librustc_driver/lib.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 58dd21c929248..41a36141cbf78 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -365,13 +365,12 @@ fn handle_explain(code: &str,
                 if dedented_line.starts_with("```") {
                     is_in_code_block = !is_in_code_block;
                     text.push_str(&line[..(indent_level+3)]);
-                    text.push('\n');
                 } else if is_in_code_block && dedented_line.starts_with("# ") {
                     continue;
                 } else {
                     text.push_str(line);
-                    text.push('\n');
                 }
+                text.push('\n');
             }
 
             show_content_with_pager(&text);
@@ -383,7 +382,7 @@ fn handle_explain(code: &str,
 }
 
 fn show_content_with_pager(content: &String) {
-    let pager_name = env::var_os("PAGER").unwrap_or(if cfg!(windows) {
+    let pager_name = env::var_os("PAGER").unwrap_or_else(|| if cfg!(windows) {
         OsString::from("more.com")
     } else {
         OsString::from("less")

From 7b0a7fdaf250ba5b5c436c8de9aacf94b519b57f Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizc@gmail.com>
Date: Sun, 2 Jul 2017 23:27:10 +0300
Subject: [PATCH 25/52] do not spawn pager if not tty

---
 src/Cargo.lock                 | 12 ++++++++++++
 src/librustc_driver/Cargo.toml |  1 +
 src/librustc_driver/lib.rs     |  9 ++++++++-
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/Cargo.lock b/src/Cargo.lock
index 2d42903ad0a7d..075a2167ea35d 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -551,6 +551,16 @@ dependencies = [
  "xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "isatty"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "itoa"
 version = "0.3.1"
@@ -1202,6 +1212,7 @@ dependencies = [
  "arena 0.0.0",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
+ "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc_macro_plugin 0.0.0",
  "rustc 0.0.0",
@@ -2056,6 +2067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum handlebars 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)" = "15bdf598fc3c2de40c6b340213028301c0d225eea55a2294e6cc148074e557a1"
 "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
 "checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37"
+"checksum isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa500db770a99afe2a0f2229be2a3d09c7ed9d7e4e8440bf71253141994e240f"
 "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
 "checksum jobserver 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4e28adc987f6d0521ef66ad60b055968107b164b3bb3cf3dc8474e0a380474a6"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 2e949f48c175e..6415dbccbfc41 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -35,3 +35,4 @@ serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
+isatty = "0.1"
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 41a36141cbf78..2ecbb89361e62 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -56,6 +56,7 @@ extern crate log;
 extern crate syntax;
 extern crate syntax_ext;
 extern crate syntax_pos;
+extern crate isatty;
 
 use driver::CompileController;
 use pretty::{PpMode, UserIdentifiedItem};
@@ -100,6 +101,8 @@ use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
 use syntax_pos::{DUMMY_SP, MultiSpan};
 
+use isatty::stdout_isatty;
+
 #[cfg(test)]
 pub mod test;
 
@@ -373,7 +376,11 @@ fn handle_explain(code: &str,
                 text.push('\n');
             }
 
-            show_content_with_pager(&text);
+            if stdout_isatty() {
+                show_content_with_pager(&text);
+            } else {
+                print!("{}", text);
+            }
         }
         None => {
             early_error(output, &format!("no extended information for {}", code));

From 0e18a9cd55826eca5f2804a06527541140a71925 Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizc@gmail.com>
Date: Mon, 3 Jul 2017 01:34:25 +0300
Subject: [PATCH 26/52] use embedded implementation instead of istty crate

---
 src/librustc_driver/lib.rs | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 2ecbb89361e62..934015c95366b 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -56,7 +56,6 @@ extern crate log;
 extern crate syntax;
 extern crate syntax_ext;
 extern crate syntax_pos;
-extern crate isatty;
 
 use driver::CompileController;
 use pretty::{PpMode, UserIdentifiedItem};
@@ -101,8 +100,6 @@ use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
 use syntax_pos::{DUMMY_SP, MultiSpan};
 
-use isatty::stdout_isatty;
-
 #[cfg(test)]
 pub mod test;
 
@@ -347,6 +344,35 @@ pub trait CompilerCalls<'a> {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
+/**
+ * TODO remove these and use winapi 0.3 instead
+ *
+ * These are duplicated in
+ *   - bootstrap/compile.rs#L478
+ *   - librustc_errors/emitter.rs#L1253
+ */
+#[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) {

From e1a91443cdd78101b0c96c84848b99e07ee133d6 Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizIO@users.noreply.github.com>
Date: Mon, 3 Jul 2017 11:45:31 +0300
Subject: [PATCH 27/52] use single line comments

---
 src/librustc_driver/lib.rs | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 934015c95366b..802ed2a489b10 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -344,17 +344,13 @@ pub trait CompilerCalls<'a> {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-/**
- * TODO remove these and use winapi 0.3 instead
- *
- * These are duplicated in
- *   - bootstrap/compile.rs#L478
- *   - librustc_errors/emitter.rs#L1253
- */
+// 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;

From 06de114f898f6f92a3c6cfb220dc957611087ef9 Mon Sep 17 00:00:00 2001
From: Cengiz Can <cengizIO@users.noreply.github.com>
Date: Mon, 3 Jul 2017 11:46:12 +0300
Subject: [PATCH 28/52] remove isatty dependency

---
 src/Cargo.lock                 | 12 ------------
 src/librustc_driver/Cargo.toml |  1 -
 2 files changed, 13 deletions(-)

diff --git a/src/Cargo.lock b/src/Cargo.lock
index 075a2167ea35d..2d42903ad0a7d 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -551,16 +551,6 @@ dependencies = [
  "xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "isatty"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "itoa"
 version = "0.3.1"
@@ -1212,7 +1202,6 @@ dependencies = [
  "arena 0.0.0",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
- "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc_macro_plugin 0.0.0",
  "rustc 0.0.0",
@@ -2067,7 +2056,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum handlebars 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)" = "15bdf598fc3c2de40c6b340213028301c0d225eea55a2294e6cc148074e557a1"
 "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
 "checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37"
-"checksum isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa500db770a99afe2a0f2229be2a3d09c7ed9d7e4e8440bf71253141994e240f"
 "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
 "checksum jobserver 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4e28adc987f6d0521ef66ad60b055968107b164b3bb3cf3dc8474e0a380474a6"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 6415dbccbfc41..2e949f48c175e 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -35,4 +35,3 @@ serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
-isatty = "0.1"

From 3ba0f07f08516c365bc33615e162f83ab182f0b5 Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Mon, 3 Jul 2017 16:16:45 +0200
Subject: [PATCH 29/52] Make sNaN removal code tolerate different sNaN
 encodings

IEEE 754-1985 specifies the encoding of NaN floating point numbers,
but while it mentions that NaNs can be subdivided into signaling
and quiet ones, it doesn't fix the encoding of signaling NaNs in binary
formats. This led to different implementations (CPUs) having different
encodings. IEEE 754-2008 finally specified the encoding of signaling NaNs
but some architectures are compatible with it, while others aren't.
Certain MIPS and PA-RISC CPUs have different encodings for signaling
NaNs.

In order to have the float <-> binary cast feature of the std library be
portable to them, we don't mask any quiet NaNs like we did before (only
being compliant to IEEE 754-2008 and nothing else), but instead we
simply pass a known good NaN instead.

Note that in the code removed there was a bug; the 64 bit mask for quiet
NaNs should have been `0x0008000000000000` instead of the specified
`0x0001000000000000`.
---
 src/libstd/f32.rs | 24 ++++++++++++++++--------
 src/libstd/f64.rs | 13 ++++++++-----
 2 files changed, 24 insertions(+), 13 deletions(-)

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) }
     }

From d68c3ab17b6f6c3b71d0531063aec8e64098f59c Mon Sep 17 00:00:00 2001
From: Anders Kaseorg <andersk@mit.edu>
Date: Mon, 3 Jul 2017 17:18:01 -0400
Subject: [PATCH 30/52] Document unintuitive argument order for Vec::dedup_by
 relation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When trying to use dedup_by to merge some auxiliary information from
removed elements into kept elements, I was surprised to observe that
vec.dedup_by(same_bucket) calls same_bucket(a, b) where b appears
before a in the vector, and discards a when true is returned.  This
argument order is probably a bug, but since it has already been
stabilized, I guess we should document it as a feature and move on.

(Vec::dedup also uses == with this unexpected argument order, but I
figure that’s not important since == is expected to be symmetric with
no side effects.)

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 src/liballoc/tests/vec.rs |  5 +++++
 src/liballoc/vec.rs       | 11 +++++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

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/vec.rs b/src/liballoc/vec.rs
index 5d1999a42629a..1a5975686df68 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -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.
     ///

From dcd7c5f4e8356c786923f86dc544aff03fba29bb Mon Sep 17 00:00:00 2001
From: Steven Fackler <sfackler@gmail.com>
Date: Mon, 3 Jul 2017 13:46:37 -1000
Subject: [PATCH 31/52] Add a stability marker for core::cmp::Reverse.0

Closes #43027
---
 src/libcore/cmp.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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> {

From 857d9dbabab5cb2ad8809e46703f77071278954a Mon Sep 17 00:00:00 2001
From: Lee Bousfield <ljbousfield@gmail.com>
Date: Mon, 3 Jul 2017 22:04:57 -0400
Subject: [PATCH 32/52] README: note how to enable debugging for rustc

---
 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

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

From 558ce91e09226abb12b70cf03df133224c467376 Mon Sep 17 00:00:00 2001
From: Stjepan Glavina <stjepang@gmail.com>
Date: Tue, 4 Jul 2017 15:14:08 +0200
Subject: [PATCH 33/52] Minor fix in docs for Vec

---
 src/liballoc/vec.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index e118d406ecf09..6918e057ab104 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -221,7 +221,7 @@ use raw_vec::RawVec;
 /// 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.
 ///

From 01e83a362ca2eee456e222e72cc6b65b951920dc Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Wed, 21 Jun 2017 11:15:49 -0600
Subject: [PATCH 34/52] Don't allocate args in order to run find.

---
 src/bootstrap/flags.rs | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index dc9dac7362788..cb455ca6a14e5 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -122,16 +122,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

From 7ed4ee272e5adf8cd267278acb62b9d9312ee34b Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Wed, 21 Jun 2017 17:03:14 -0600
Subject: [PATCH 35/52] Clean up and restructure sanity checking.

---
 src/bootstrap/config.rs |   1 +
 src/bootstrap/flags.rs  |   2 +-
 src/bootstrap/sanity.rs | 143 +++++++++++++++++++---------------------
 3 files changed, 69 insertions(+), 77 deletions(-)

diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 3ada846e38236..12862e136dabe 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -119,6 +119,7 @@ pub struct Config {
 /// 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>,
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index cb455ca6a14e5..029118eb647b0 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -163,7 +163,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;
                 }
             },
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 46d047bb015e5..41482ac57f9c5 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,9 +29,46 @@ 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);
+                }
+            }
+            return 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
@@ -41,33 +78,12 @@ pub fn check(build: &mut Build) {
             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());
+        cmd_finder.must_have("git");
     }
 
     // We need cmake, but only if we're actually building LLVM or sanitizers.
@@ -75,57 +91,34 @@ 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());
+        if 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")));
 
-    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);
-        }
-    }
+    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 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,18 +126,17 @@ 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;
         }
@@ -156,7 +148,7 @@ pub fn check(build: &mut Build) {
         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") {
@@ -208,13 +200,12 @@ $ 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);
+            panic!("specified host `{}` is not in configuration", host);
         }
     }
     for target in build.flags.target.iter() {
         if !build.config.target.contains(target) {
-            panic!("specified target `{}` is not in the ./configure list",
-                   target);
+            panic!("specified target `{}` is not in configuration", target);
         }
     }
 
@@ -231,6 +222,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);
     }
 }

From d3bf6e562ecab27844924af741412865babeed84 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Sat, 24 Jun 2017 05:42:38 -0600
Subject: [PATCH 36/52] Remove 'static lifetimes from channels.

---
 src/bootstrap/channel.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index 4664b1f765e63..db0691fb1c2e9 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>,

From 5b44cbc39fc591cfc0339ad641be393c4a2612f1 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Mon, 26 Jun 2017 10:23:50 -0600
Subject: [PATCH 37/52] Cleanups to check code.

---
 src/bootstrap/check.rs | 41 ++++++++++++++++++-----------------------
 1 file changed, 18 insertions(+), 23 deletions(-)

diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 277728b90b763..a542200bbbad3 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)]
@@ -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);
+    build.prepare_tool_cmd(&compiler, &mut cmd);
     try_run(build, cmd.arg(&build.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,9 +123,8 @@ 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"));
@@ -200,7 +198,7 @@ pub fn compiletest(build: &Build,
     cmd.arg("--host").arg(compiler.host);
     cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
 
-    if let Some(nodejs) = build.config.nodejs.as_ref() {
+    if let Some(ref nodejs) = build.config.nodejs {
         cmd.arg("--nodejs").arg(nodejs);
     }
 
@@ -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,9 +537,8 @@ 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),
                           "remote-test-client");
@@ -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) {

From 388fca81f6605ce32a79d484723262f0e50965e4 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Mon, 26 Jun 2017 18:13:10 -0600
Subject: [PATCH 38/52] Cleanup compile.rs.

---
 src/bootstrap/compile.rs | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index b2bd792e93ba6..61840d81b52e2 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);
     }
 
@@ -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");
@@ -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

From c6ece966ac6745f71f21f98454193e41ad85fe42 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 09:05:40 -0600
Subject: [PATCH 39/52] Cleanup utils

---
 src/bootstrap/util.rs | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

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
+}

From 802b6db0041115d261f3d0ea1855f35658141c0b Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 09:05:47 -0600
Subject: [PATCH 40/52] Cleanup dist

---
 src/bootstrap/dist.rs | 32 +++++++++++---------------------
 1 file changed, 11 insertions(+), 21 deletions(-)

diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 753bd1df0d83f..cfcba07228b1e 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -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") {
@@ -595,7 +585,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) {

From 6766abbfa9959581ebfdba32131125e2b3b624f3 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 09:51:26 -0600
Subject: [PATCH 41/52] Clippy lints

---
 src/bootstrap/channel.rs |  2 +-
 src/bootstrap/compile.rs | 17 +++++++++--------
 src/bootstrap/config.rs  |  2 +-
 src/bootstrap/dist.rs    | 11 +++++------
 src/bootstrap/flags.rs   |  6 ++----
 src/bootstrap/install.rs |  2 +-
 src/bootstrap/lib.rs     | 14 +++++++-------
 src/bootstrap/sanity.rs  | 18 +++++++-----------
 src/bootstrap/step.rs    |  8 ++++----
 9 files changed, 37 insertions(+), 43 deletions(-)

diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index db0691fb1c2e9..199c01cf82152 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -99,6 +99,6 @@ impl GitInfo {
             version.push_str(&inner.commit_date);
             version.push_str(")");
         }
-        return version
+        version
     }
 }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 61840d81b52e2..5123e59a5dbbe 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -559,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 12862e136dabe..56808d69ee2c7 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -417,7 +417,7 @@ impl Config {
             config.update_with_config_mk();
         }
 
-        return config
+        config
     }
 
     /// "Temporary" routine to parse `config.mk` into this configuration.
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index cfcba07228b1e..8e3f88c8a3485 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -488,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);
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 029118eb647b0..1a73c48966598 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -315,10 +315,8 @@ 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);
         }
 
         Flags {
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..35abe21452372 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -496,7 +496,7 @@ impl Build {
 
         self.ci_env.force_coloring_in_ci(&mut cargo);
 
-        return cargo
+        cargo
     }
 
     /// Get a path to the compiler specified.
@@ -519,7 +519,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 +527,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 +578,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 +587,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.
@@ -834,7 +834,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 +866,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
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 41482ac57f9c5..d6def25cfaa94 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -56,7 +56,7 @@ impl Finder {
                     return Some(target);
                 }
             }
-            return None;
+            None
         }).clone()
     }
 
@@ -73,10 +73,8 @@ pub fn check(build: &mut Build) {
     // 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 mut cmd_finder = Finder::new();
@@ -95,12 +93,10 @@ pub fn check(build: &mut Build) {
     }
 
     // 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 cmd_finder.maybe_have("ninja-build").is_none() {
-            cmd_finder.must_have("ninja");
-        }
+    // 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");
     }
 
     build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 5f0724c657757..61e9a0d16dac0 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -148,7 +148,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                 }
             }
         }
-        return ret
+        ret
     };
 
     // ========================================================================
@@ -237,7 +237,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                          s.target)
                 }
             });
-            return rule
+            rule
     }
 
     // Similar to the `libstd`, `libtest`, and `librustc` rules above, except
@@ -1326,7 +1326,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 +1365,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

From 743af95d4be6423a4123aa81bf587756d006ed9c Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 13:24:37 -0600
Subject: [PATCH 42/52] Update a few comments.

---
 src/bootstrap/bin/rustc.rs | 15 +++++----------
 src/bootstrap/lib.rs       | 14 ++++++--------
 2 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 8c6eaee24f294..7232208b52234 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 {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 35abe21452372..91ace0805e43e 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -175,7 +175,9 @@ pub struct Build {
     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,
@@ -202,20 +204,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,
 }
 

From 2cc5b084a0fdbd08ecc873be33bafd08d4faf273 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 13:32:04 -0600
Subject: [PATCH 43/52] Clarify meaning of Build.cargo, Build.rustc.

Rename Build.{cargo, rustc} to {initial_cargo, initial_rustc}.
---
 src/bootstrap/check.rs    |  8 ++++----
 src/bootstrap/config.rs   | 26 ++++++++++++++++++++------
 src/bootstrap/dist.rs     |  8 ++++----
 src/bootstrap/flags.rs    |  9 +++++++--
 src/bootstrap/lib.rs      | 38 ++++++++++++++------------------------
 src/bootstrap/metadata.rs |  2 +-
 6 files changed, 50 insertions(+), 41 deletions(-)

diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index a542200bbbad3..04ae7e1e00921 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -109,7 +109,7 @@ 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)
+    try_run(build, cmd.arg(&build.initial_cargo)
                       .arg(&out_dir)
                       .env("RUSTC", build.compiler_path(&compiler))
                       .env("RUSTDOC", build.rustdoc(&compiler)));
@@ -654,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)
@@ -663,12 +663,12 @@ 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);
+       .env("RUSTC", &build.initial_rustc);
     if build.flags.cmd.no_fail_fast() {
         cmd.arg("--no-fail-fast");
     }
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 56808d69ee2c7..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,6 +112,12 @@ 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.
@@ -308,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);
@@ -411,6 +413,18 @@ 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() {
@@ -610,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 8e3f88c8a3485..c91d6f0b77cbd 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -626,23 +626,23 @@ pub fn plain_source_tarball(build: &Build) {
     if build.src_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);
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 1a73c48966598..4541b6623c493 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -35,7 +35,7 @@ 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,
@@ -319,6 +319,11 @@ Arguments:
             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,
@@ -330,7 +335,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"),
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 91ace0805e43e..bb82e711d7bf0 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -161,8 +161,6 @@ pub struct Build {
     flags: Flags,
 
     // Derived properties from the above two configurations
-    cargo: PathBuf,
-    rustc: PathBuf,
     src: PathBuf,
     out: PathBuf,
     rust_info: channel::GitInfo,
@@ -170,6 +168,10 @@ pub struct Build {
     rls_info: channel::GitInfo,
     local_rebuild: bool,
 
+    // 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>,
@@ -224,22 +226,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") {
@@ -255,17 +244,18 @@ impl Build {
         let src_is_git = src.join(".git").exists();
 
         Build {
+            initial_rustc: config.initial_rustc.clone(),
+            initial_cargo: config.initial_cargo.clone(),
+            local_rebuild: config.local_rebuild,
+
             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(),
@@ -294,7 +284,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();
@@ -336,7 +326,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)
@@ -420,7 +410,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))
@@ -500,7 +490,7 @@ impl Build {
     /// 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))
         }
@@ -758,7 +748,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))
     }
 
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"));

From 712bd0d841469f8ed42d555ed714fee06beb14fa Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 13:34:26 -0600
Subject: [PATCH 44/52] Remove src_is_git, instead call method on rust_info
 directly.

---
 src/bootstrap/channel.rs | 4 ++++
 src/bootstrap/dist.rs    | 2 +-
 src/bootstrap/lib.rs     | 2 --
 src/bootstrap/sanity.rs  | 2 +-
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index 199c01cf82152..1153acfa57d39 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -101,4 +101,8 @@ impl GitInfo {
         }
         version
     }
+
+    pub fn is_git(&self) -> bool {
+        self.inner.is_some()
+    }
 }
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index c91d6f0b77cbd..2f7c1f038a198 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -623,7 +623,7 @@ 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.initial_cargo);
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index bb82e711d7bf0..a6608972acd1d 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -183,7 +183,6 @@ pub struct Build {
     cxx: HashMap<String, gcc::Tool>,
     crates: HashMap<String, Crate>,
     is_sudo: bool,
-    src_is_git: bool,
     ci_env: CiEnv,
     delayed_failures: Cell<usize>,
 }
@@ -262,7 +261,6 @@ impl Build {
             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),
         }
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index d6def25cfaa94..433ac3dedfd9e 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -80,7 +80,7 @@ pub fn check(build: &mut Build) {
     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 {
+    if build.rust_info.is_git() {
         cmd_finder.must_have("git");
     }
 

From 4dc8fe90836c622e57293c1262a9f7728e5edfc8 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 13:37:24 -0600
Subject: [PATCH 45/52] Store positive instead of negative fail_fast.

This makes later negation much easier to interpret.
---
 src/bootstrap/check.rs | 10 +++++-----
 src/bootstrap/flags.rs |  8 ++++----
 src/bootstrap/lib.rs   |  3 ++-
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 04ae7e1e00921..1ee33c1f4657c 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -59,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);
@@ -70,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);
@@ -128,7 +128,7 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
 
     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");
     }
 
@@ -448,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");
     }
 
@@ -669,7 +669,7 @@ pub fn bootstrap(build: &Build) {
        .env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
        .env("RUSTC_BOOTSTRAP", "1")
        .env("RUSTC", &build.initial_rustc);
-    if build.flags.cmd.no_fail_fast() {
+    if !build.fail_fast {
         cmd.arg("--no-fail-fast");
     }
     cmd.arg("--").args(&build.flags.cmd.test_args());
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 4541b6623c493..593b06517585a 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -61,7 +61,7 @@ pub enum Subcommand {
     Test {
         paths: Vec<PathBuf>,
         test_args: Vec<String>,
-        no_fail_fast: bool,
+        fail_fast: bool,
     },
     Bench {
         paths: Vec<PathBuf>,
@@ -278,7 +278,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" => {
@@ -354,9 +354,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/lib.rs b/src/bootstrap/lib.rs
index a6608972acd1d..978e1d2be162c 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -167,6 +167,7 @@ pub struct Build {
     cargo_info: channel::GitInfo,
     rls_info: channel::GitInfo,
     local_rebuild: bool,
+    fail_fast: bool,
 
     // Stage 0 (downloaded) compiler and cargo or their local rust equivalents.
     initial_rustc: PathBuf,
@@ -240,12 +241,12 @@ 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();
 
         Build {
             initial_rustc: config.initial_rustc.clone(),
             initial_cargo: config.initial_cargo.clone(),
             local_rebuild: config.local_rebuild,
+            fail_fast: flags.cmd.fail_fast(),
 
             flags: flags,
             config: config,

From 39cf1da81c73e9bcd7b60dad927cbe1f360bc1f3 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 13:49:21 -0600
Subject: [PATCH 46/52] Store verbosity on Build

Prevents accidental mistakes in not using the right verbosity by going
to only config or flags.
---
 src/bootstrap/check.rs |  2 +-
 src/bootstrap/flags.rs | 10 ----------
 src/bootstrap/lib.rs   | 17 +++++++++++++----
 3 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 1ee33c1f4657c..a06d925e2ef81 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -249,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");
     }
 
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 593b06517585a..5804df34e8b38 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -41,16 +41,6 @@ pub struct Flags {
     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>,
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 978e1d2be162c..be28975c3ea33 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -168,6 +168,7 @@ pub struct Build {
     rls_info: channel::GitInfo,
     local_rebuild: bool,
     fail_fast: bool,
+    verbosity: usize,
 
     // Stage 0 (downloaded) compiler and cargo or their local rust equivalents.
     initial_rustc: PathBuf,
@@ -247,6 +248,7 @@ impl Build {
             initial_cargo: config.initial_cargo.clone(),
             local_rebuild: config.local_rebuild,
             fail_fast: flags.cmd.fail_fast(),
+            verbosity: cmp::max(flags.verbose, config.verbose),
 
             flags: flags,
             config: config,
@@ -428,8 +430,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.
@@ -467,7 +468,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`
@@ -779,9 +780,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);
         }
     }

From 5809a7d0b76c7842582a43ea5516b3817b92f9d8 Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 15:52:46 -0600
Subject: [PATCH 47/52] Move targets, hosts, and build triple into Build.

---
 src/bootstrap/lib.rs    | 38 +++++++++++++++++++++++++++++++++++++-
 src/bootstrap/sanity.rs | 11 -----------
 src/bootstrap/step.rs   | 22 +++++++---------------
 3 files changed, 44 insertions(+), 27 deletions(-)

diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index be28975c3ea33..92a57630ca5b7 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -170,6 +170,11 @@ pub struct Build {
     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,
@@ -243,6 +248,27 @@ impl Build {
         let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo"));
         let rls_info = channel::GitInfo::new(&src.join("src/tools/rls"));
 
+        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(),
@@ -250,6 +276,10 @@ impl Build {
             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,
             src: src,
@@ -269,6 +299,12 @@ impl Build {
         }
     }
 
+    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 {
@@ -798,7 +834,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.
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 433ac3dedfd9e..e2c955c4f4f3a 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -194,17 +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 configuration", host);
-        }
-    }
-    for target in build.flags.target.iter() {
-        if !build.config.target.contains(target) {
-            panic!("specified target `{}` is not in configuration", target);
-        }
-    }
-
     let run = |cmd: &mut Command| {
         cmd.output().map(|output| {
             String::from_utf8_lossy(&output.stdout)
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 61e9a0d16dac0..bcfa004ac3cdd 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -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| {

From 1654a2f5aca29041df86a8edd7fc0c9e6c5c1c9b Mon Sep 17 00:00:00 2001
From: Mark Simulacrum <mark.simulacrum@gmail.com>
Date: Tue, 27 Jun 2017 15:59:43 -0600
Subject: [PATCH 48/52] Use build.build instead of build.config.build

---
 src/bootstrap/cc.rs      |  14 ++++--
 src/bootstrap/check.rs   |  16 +++---
 src/bootstrap/compile.rs |  10 ++--
 src/bootstrap/dist.rs    |  14 +++---
 src/bootstrap/doc.rs     |  18 +++----
 src/bootstrap/lib.rs     |   2 +-
 src/bootstrap/native.rs  |   8 +--
 src/bootstrap/sanity.rs  |   4 +-
 src/bootstrap/step.rs    | 104 +++++++++++++++++++--------------------
 9 files changed, 98 insertions(+), 92 deletions(-)

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/check.rs b/src/bootstrap/check.rs
index a06d925e2ef81..b3b5ae8d67d65 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -196,7 +196,7 @@ 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(ref nodejs) = build.config.nodejs {
         cmd.arg("--nodejs").arg(nodejs);
@@ -222,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)
@@ -277,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"));
     }
 
@@ -366,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);
 }
@@ -540,7 +540,7 @@ fn krate_remote(build: &Build,
     let out_dir = build.cargo_out(compiler, mode, target);
     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);
@@ -585,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")
@@ -611,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") {
@@ -636,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));
 
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 5123e59a5dbbe..5a3106c7d5e64 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -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");
@@ -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);
@@ -423,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),
@@ -443,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);
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 2f7c1f038a198..efc33bcee9b3b 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);
@@ -394,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
     }
@@ -440,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;
     }
@@ -705,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");
@@ -766,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");
@@ -1198,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/lib.rs b/src/bootstrap/lib.rs
index 92a57630ca5b7..69b0c4a2756a6 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1079,7 +1079,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/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 e2c955c4f4f3a..a9c1b023dd4f5 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -139,7 +139,7 @@ pub fn check(build: &mut Build) {
     }
 
     // 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);
     }
@@ -147,7 +147,7 @@ pub fn check(build: &mut Build) {
     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");
         }
 
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index bcfa004ac3cdd..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)
              }
          })
@@ -215,24 +215,24 @@ 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)
                 }
@@ -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(),
@@ -1486,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")));
@@ -1509,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")));
@@ -1537,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"));
@@ -1567,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"));
@@ -1604,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"));
@@ -1631,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"));
@@ -1675,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)

From 7e6c9f363501c49d3a1f666d85d41891f50890b8 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 22 Jun 2017 13:14:00 -0700
Subject: [PATCH 49/52] Switch to rust-lang-nursery/compiler-builtins

This commit migrates the in-tree `libcompiler_builtins` to the upstream version
at https://github.com/rust-lang-nursery/compiler-builtins. The upstream version
has a number of intrinsics written in Rust and serves as an in-progress rewrite
of compiler-rt into Rust. Additionally it also contains all the existing
intrinsics defined in `libcompiler_builtins` for 128-bit integers.

It's been the intention since the beginning to make this transition but
previously it just lacked the manpower to get done. As this PR likely shows it
wasn't a trivial integration! Some highlight changes are:

* The PR rust-lang-nursery/compiler-builtins#166 contains a number of fixes
  across platforms and also some refactorings to make the intrinsics easier to
  read. The additional testing added there also fixed a number of integration
  issues when pulling the repository into this tree.

* LTO with the compiler-builtins crate was fixed to link in the entire crate
  after the LTO process as these intrinsics are excluded from LTO.

* Treatment of hidden symbols was updated as previously the
  `#![compiler_builtins]` crate would mark all symbol *imports* as hidden
  whereas it was only intended to mark *exports* as hidden.
---
 .gitmodules                                   |   6 +-
 src/Cargo.lock                                |   1 -
 src/bootstrap/bin/rustc.rs                    |  19 +-
 src/bootstrap/bootstrap.py                    |   2 +-
 src/bootstrap/dist.rs                         |   2 +-
 src/build_helper/lib.rs                       |   5 +-
 src/ci/init_repo.sh                           |   7 +-
 src/compiler-rt                               |   1 -
 .../library-features/compiler-builtins-lib.md |  35 -
 src/libcompiler_builtins                      |   1 +
 src/libcompiler_builtins/Cargo.toml           |  19 -
 src/libcompiler_builtins/build.rs             | 423 ----------
 src/libcompiler_builtins/lib.rs               | 721 ------------------
 src/libprofiler_builtins/build.rs             |   2 +-
 src/librustc_trans/attributes.rs              |   2 +-
 src/librustc_trans/back/link.rs               |  27 +-
 src/librustc_trans/back/write.rs              |   3 +-
 src/librustc_trans/declare.rs                 |  11 -
 src/librustc_trans/trans_item.rs              |  12 +
 src/libstd/Cargo.toml                         |   2 +-
 src/rustc/compiler_builtins_shim/Cargo.toml   |  24 +
 .../compiler_builtins_shim/build.rs}          |  13 +-
 src/test/run-pass/lib-defaults.rs             |   9 +-
 src/test/run-pass/rfc1717/library-override.rs |   7 +-
 src/tools/tidy/src/lib.rs                     |   1 +
 25 files changed, 110 insertions(+), 1245 deletions(-)
 delete mode 160000 src/compiler-rt
 delete mode 100644 src/doc/unstable-book/src/library-features/compiler-builtins-lib.md
 create mode 160000 src/libcompiler_builtins
 delete mode 100644 src/libcompiler_builtins/Cargo.toml
 delete mode 100644 src/libcompiler_builtins/build.rs
 delete mode 100644 src/libcompiler_builtins/lib.rs
 create mode 100644 src/rustc/compiler_builtins_shim/Cargo.toml
 rename src/{test/run-pass/auxiliary/clibrary.rs => rustc/compiler_builtins_shim/build.rs} (62%)

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/src/Cargo.lock b/src/Cargo.lock
index 2d42903ad0a7d..cf4c3dce6e35a 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -273,7 +273,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)",
 ]
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 8c6eaee24f294..fbb2ae29ef2ea 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -142,6 +142,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 +155,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 +170,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/dist.rs b/src/bootstrap/dist.rs
index 753bd1df0d83f..3bf1b82b0a88a 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -564,10 +564,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",
     ];
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/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/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/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/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..b32e1d4aa8dda 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -363,6 +363,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,
@@ -698,7 +716,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));
     });
@@ -1247,7 +1268,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/write.rs b/src/librustc_trans/back/write.rs
index 562d7171156fe..1703a121e17d5 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -1200,8 +1200,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/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/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/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/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/auxiliary/clibrary.rs b/src/rustc/compiler_builtins_shim/build.rs
similarity index 62%
rename from src/test/run-pass/auxiliary/clibrary.rs
rename to src/rustc/compiler_builtins_shim/build.rs
index 7438ba21bfc4a..546f60482e7bc 100644
--- a/src/test/run-pass/auxiliary/clibrary.rs
+++ b/src/rustc/compiler_builtins_shim/build.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,8 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// no-prefer-dynamic
-#![crate_type = "staticlib"]
+#![deny(warnings)]
 
-#[no_mangle]
-pub extern "C" fn foo(x:i32) -> i32 { x }
+// See comments in Cargo.toml for why this exists
+
+fn main() {
+    println!("cargo:rustc-cfg=stdbuild");
+    println!("cargo:rerun-if-changed=build.rs");
+}
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/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/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",

From 78fdbfc4008b52bcce201fd589ed84d2abb0419d Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 5 Jul 2017 13:51:34 -0700
Subject: [PATCH 50/52] rustbuild: Only -Zsave-analysis for libstd

Don't pass the flag when we're compiling the compiler or other related tools
---
 src/bootstrap/lib.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 69b0c4a2756a6..5a3785b1ed634 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -482,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());
         }
 

From 695dee063bcd40f154bb27b7beafcb3d4dd775ac Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Sat, 3 Jun 2017 14:54:08 -0700
Subject: [PATCH 51/52] rustc: Implement the #[global_allocator] attribute

This PR is an implementation of [RFC 1974] which specifies a new method of
defining a global allocator for a program. This obsoletes the old
`#![allocator]` attribute and also removes support for it.

[RFC 1974]: https://github.com/rust-lang/rfcs/pull/197

The new `#[global_allocator]` attribute solves many issues encountered with the
`#![allocator]` attribute such as composition and restrictions on the crate
graph itself. The compiler now has much more control over the ABI of the
allocator and how it's implemented, allowing much more freedom in terms of how
this feature is implemented.

cc #27389
---
 src/Cargo.lock                                |  18 +
 .../language-features/allocator-internals.md  |   7 +
 .../src/language-features/allocator.md        | 119 -----
 .../src/language-features/global-allocator.md |  71 +++
 src/liballoc/allocator.rs                     |  23 +-
 src/liballoc/arc.rs                           |  10 +-
 src/liballoc/boxed.rs                         |  27 +-
 src/liballoc/btree/node.rs                    |  26 +-
 src/liballoc/heap.rs                          | 353 ++++++-------
 src/liballoc/lib.rs                           |   6 +-
 src/liballoc/oom.rs                           |  61 ---
 src/liballoc/raw_vec.rs                       |  22 +-
 src/liballoc/rc.rs                            |  11 +-
 src/liballoc_jemalloc/Cargo.toml              |   4 +
 src/liballoc_jemalloc/lib.rs                  | 201 ++++---
 src/liballoc_system/Cargo.toml                |   3 +
 src/liballoc_system/lib.rs                    | 479 ++++++++++++-----
 src/liballoc_system/old.rs                    | 268 ++++++++++
 src/libcollections/lib.rs                     |   2 -
 src/librustc/lib.rs                           |   1 +
 src/librustc/middle/allocator.rs              |  26 +
 src/librustc/middle/dead.rs                   |   5 +
 src/librustc/middle/dependency_format.rs      |  29 +-
 src/librustc/session/mod.rs                   |   8 +-
 src/librustc_allocator/Cargo.toml             |  15 +
 src/librustc_allocator/expand.rs              | 498 ++++++++++++++++++
 src/librustc_allocator/lib.rs                 | 101 ++++
 src/librustc_asan/Cargo.toml                  |   1 +
 src/librustc_asan/lib.rs                      |   9 +
 .../target/aarch64_unknown_freebsd.rs         |   2 +-
 .../target/aarch64_unknown_linux_gnu.rs       |   2 +-
 src/librustc_back/target/bitrig_base.rs       |   1 -
 src/librustc_back/target/fuchsia_base.rs      |   1 -
 .../target/mips64_unknown_linux_gnuabi64.rs   |   2 +-
 .../target/mips64el_unknown_linux_gnuabi64.rs |   2 +-
 .../target/mips_unknown_linux_gnu.rs          |   2 +-
 .../target/mips_unknown_linux_musl.rs         |   2 +-
 .../target/mips_unknown_linux_uclibc.rs       |   2 +-
 .../target/mipsel_unknown_linux_gnu.rs        |   2 +-
 .../target/mipsel_unknown_linux_musl.rs       |   2 +-
 .../target/mipsel_unknown_linux_uclibc.rs     |   2 +-
 src/librustc_back/target/mod.rs               |  18 +-
 src/librustc_back/target/openbsd_base.rs      |   1 -
 .../target/powerpc64_unknown_linux_gnu.rs     |   2 +-
 .../target/powerpc64le_unknown_linux_gnu.rs   |   2 +-
 .../target/powerpc_unknown_linux_gnu.rs       |   2 +-
 src/librustc_back/target/redox_base.rs        |   2 -
 .../target/s390x_unknown_linux_gnu.rs         |   2 +-
 .../target/sparc64_unknown_linux_gnu.rs       |   2 +-
 src/librustc_back/target/windows_msvc_base.rs |   1 -
 .../target/x86_64_rumprun_netbsd.rs           |   2 +-
 src/librustc_driver/Cargo.toml                |   1 +
 src/librustc_driver/driver.rs                 |   8 +
 src/librustc_driver/lib.rs                    |   1 +
 src/librustc_lint/builtin.rs                  |   3 +-
 src/librustc_llvm/ffi.rs                      |   1 +
 src/librustc_lsan/Cargo.toml                  |   1 +
 src/librustc_lsan/lib.rs                      |   9 +
 src/librustc_metadata/creader.rs              | 192 +++++--
 src/librustc_metadata/cstore.rs               |  21 +-
 src/librustc_metadata/cstore_impl.rs          |   1 -
 src/librustc_metadata/encoder.rs              |   5 +
 src/librustc_metadata/schema.rs               |   2 +
 src/librustc_msan/Cargo.toml                  |   1 +
 src/librustc_msan/lib.rs                      |   9 +
 src/librustc_trans/Cargo.toml                 |   1 +
 src/librustc_trans/allocator.rs               | 117 ++++
 src/librustc_trans/back/link.rs               |  58 +-
 src/librustc_trans/back/symbol_export.rs      |   1 -
 src/librustc_trans/back/write.rs              |  20 +
 src/librustc_trans/base.rs                    |  40 ++
 src/librustc_trans/lib.rs                     |   3 +
 src/libstd/collections/hash/table.rs          |  11 +-
 src/libstd/error.rs                           |   4 +-
 src/libstd/heap.rs                            | 165 ++++++
 src/libstd/lib.rs                             |  14 +-
 src/libstd/sys/unix/mod.rs                    |  20 -
 src/libstd/sys/windows/mod.rs                 |  18 -
 src/libsyntax/ext/build.rs                    |   6 +
 src/libsyntax/feature_gate.rs                 |  24 +-
 src/rustllvm/llvm-rebuild-trigger             |   4 +
 src/test/codegen/function-arguments.rs        |   2 +-
 .../allocator-depends-on-needs-allocators.rs  |  21 -
 .../compile-fail/allocator-dylib-is-system.rs |  41 --
 .../allocator-rust-dylib-is-jemalloc.rs       |  41 --
 .../auxiliary/system-allocator.rs}            |  10 +-
 .../auxiliary/system-allocator2.rs}           |  11 +-
 .../allocator/function-allocator.rs           |  16 +
 .../allocator/not-an-allocator.rs             |  26 +
 .../{ => allocator}/two-allocators.rs         |  15 +-
 .../compile-fail/allocator/two-allocators2.rs |  25 +
 .../allocator/two-allocators3.rs}             |  14 +-
 ...rs => feature-gate-allocator_internals.rs} |   7 +-
 ...r1.rs => feature-gate-global_allocator.rs} |  10 +-
 src/test/compile-fail/two-allocators-2.rs     |  21 -
 src/test/compile-fail/two-allocators-3.rs     |  23 -
 src/test/run-make/no-duplicate-libs/Makefile  |   4 +-
 .../no-duplicate-libs/bar.c}                  |   8 +-
 src/test/run-make/no-duplicate-libs/bar.rs    |  25 -
 .../no-duplicate-libs/foo.c}                  |   5 +-
 src/test/run-make/no-duplicate-libs/foo.rs    |  25 -
 src/test/run-make/no-duplicate-libs/main.rs   |   6 +-
 src/test/run-pass/allocator-alloc-one.rs      |  13 +-
 src/test/run-pass/allocator-default.rs        |  19 -
 src/test/run-pass/allocator-override.rs       |  29 -
 .../allocator/auxiliary/custom-as-global.rs   |  27 +
 .../run-pass/allocator/auxiliary/custom.rs    |  31 ++
 .../allocator/auxiliary/helper.rs}            |  11 +-
 src/test/run-pass/allocator/custom.rs         |  68 +++
 src/test/run-pass/allocator/xcrate-use.rs     |  44 ++
 src/test/run-pass/allocator/xcrate-use2.rs    |  57 ++
 src/test/run-pass/lib-defaults.rs             |   9 +-
 src/test/run-pass/realloc-16687.rs            |  75 +--
 src/test/run-pass/rfc1717/library-override.rs |   7 +-
 src/test/run-pass/smallest-hello-world.rs     |  30 +-
 115 files changed, 2828 insertions(+), 1169 deletions(-)
 create mode 100644 src/doc/unstable-book/src/language-features/allocator-internals.md
 delete mode 100644 src/doc/unstable-book/src/language-features/allocator.md
 create mode 100644 src/doc/unstable-book/src/language-features/global-allocator.md
 delete mode 100644 src/liballoc/oom.rs
 create mode 100644 src/liballoc_system/old.rs
 create mode 100644 src/librustc/middle/allocator.rs
 create mode 100644 src/librustc_allocator/Cargo.toml
 create mode 100644 src/librustc_allocator/expand.rs
 create mode 100644 src/librustc_allocator/lib.rs
 create mode 100644 src/librustc_trans/allocator.rs
 create mode 100644 src/libstd/heap.rs
 delete mode 100644 src/test/compile-fail/allocator-depends-on-needs-allocators.rs
 delete mode 100644 src/test/compile-fail/allocator-dylib-is-system.rs
 delete mode 100644 src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
 rename src/test/compile-fail/{auxiliary/allocator3.rs => allocator/auxiliary/system-allocator.rs} (71%)
 rename src/test/compile-fail/{auxiliary/allocator2.rs => allocator/auxiliary/system-allocator2.rs} (71%)
 create mode 100644 src/test/compile-fail/allocator/function-allocator.rs
 create mode 100644 src/test/compile-fail/allocator/not-an-allocator.rs
 rename src/test/compile-fail/{ => allocator}/two-allocators.rs (59%)
 create mode 100644 src/test/compile-fail/allocator/two-allocators2.rs
 rename src/test/{run-pass/allocator-system.rs => compile-fail/allocator/two-allocators3.rs} (60%)
 rename src/test/compile-fail/{auxiliary/allocator-dylib.rs => feature-gate-allocator_internals.rs} (72%)
 rename src/test/compile-fail/{auxiliary/allocator1.rs => feature-gate-global_allocator.rs} (70%)
 delete mode 100644 src/test/compile-fail/two-allocators-2.rs
 delete mode 100644 src/test/compile-fail/two-allocators-3.rs
 rename src/test/{compile-fail/feature-gate-allocator.rs => run-make/no-duplicate-libs/bar.c} (76%)
 delete mode 100644 src/test/run-make/no-duplicate-libs/bar.rs
 rename src/test/{compile-fail/auxiliary/allocator-dylib2.rs => run-make/no-duplicate-libs/foo.c} (83%)
 delete mode 100644 src/test/run-make/no-duplicate-libs/foo.rs
 delete mode 100644 src/test/run-pass/allocator-default.rs
 delete mode 100644 src/test/run-pass/allocator-override.rs
 create mode 100644 src/test/run-pass/allocator/auxiliary/custom-as-global.rs
 create mode 100644 src/test/run-pass/allocator/auxiliary/custom.rs
 rename src/test/{compile-fail/auxiliary/needs_allocator.rs => run-pass/allocator/auxiliary/helper.rs} (77%)
 create mode 100644 src/test/run-pass/allocator/custom.rs
 create mode 100644 src/test/run-pass/allocator/xcrate-use.rs
 create mode 100644 src/test/run-pass/allocator/xcrate-use2.rs

diff --git a/src/Cargo.lock b/src/Cargo.lock
index 2d42903ad0a7d..cb3efea0d9f01 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",
 ]
@@ -1127,10 +1130,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)",
@@ -1205,6 +1219,7 @@ dependencies = [
  "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 +1288,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 +1333,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 +1416,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/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/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_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/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/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/dead.rs b/src/librustc/middle/dead.rs
index 6077b7863e2c3..77b4c977d289e 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 {
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/session/mod.rs b/src/librustc/session/mod.rs
index 8bafdda234a09..39a719faa123e 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 {
@@ -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),
@@ -732,7 +738,6 @@ pub fn build_session_(sopts: config::Options,
         print_fuel_crate: print_fuel_crate,
         print_fuel: 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_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml
new file mode 100644
index 0000000000000..e3d1d8e32c4b7
--- /dev/null
+++ b/src/librustc_allocator/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_allocator"
+version = "0.0.0"
+
+[lib]
+path = "lib.rs"
+crate-type = ["dylib"]
+test = false
+
+[dependencies]
+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..def72752389e9 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -15,6 +15,7 @@ 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..add827536c877 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;
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..35ce993d33557 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -134,7 +134,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()) }
 }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e9701b95002d4..47f586ac89529 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()
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/back/link.rs b/src/librustc_trans/back/link.rs
index a7f205a18a46c..6f235ae5ee049 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
@@ -417,11 +424,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 +494,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 +506,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 +570,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 +644,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 +700,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| {
@@ -944,6 +982,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 {
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..0c233dfe109bc 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:
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/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/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/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/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/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 412a34932087d..2cfb16169273f 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,
@@ -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/feature_gate.rs b/src/libsyntax/feature_gate.rs
index df8ee189d21b3..0163bb3b1d05a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -137,7 +137,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 +359,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 +382,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 +589,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 \
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/allocator2.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
similarity index 71%
rename from src/test/compile-fail/auxiliary/allocator2.rs
rename to src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
index b24784838d00b..4761dc421d7f7 100644
--- a/src/test/compile-fail/auxiliary/allocator2.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(allocator)]
-#![allocator]
+#![feature(global_allocator, allocator_api)]
 #![crate_type = "rlib"]
-#![no_std]
+
+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/run-pass/allocator-system.rs b/src/test/compile-fail/allocator/two-allocators3.rs
similarity index 60%
rename from src/test/run-pass/allocator-system.rs
rename to src/test/compile-fail/allocator/two-allocators3.rs
index 4585003d5793b..c310d94f6dfd8 100644
--- a/src/test/run-pass/allocator-system.rs
+++ b/src/test/compile-fail/allocator/two-allocators3.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,14 @@
 // 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(alloc_system)]
+#![feature(global_allocator)]
 
-extern crate alloc_system;
+extern crate system_allocator;
+extern crate system_allocator2;
 
-fn main() {
-    println!("{:?}", Box::new(3));
-}
+fn main() {}
diff --git a/src/test/compile-fail/auxiliary/allocator-dylib.rs b/src/test/compile-fail/feature-gate-allocator_internals.rs
similarity index 72%
rename from src/test/compile-fail/auxiliary/allocator-dylib.rs
rename to src/test/compile-fail/feature-gate-allocator_internals.rs
index 568b247ecdbf3..b519a985ec5e7 100644
--- a/src/test/compile-fail/auxiliary/allocator-dylib.rs
+++ b/src/test/compile-fail/feature-gate-allocator_internals.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
+#![default_lib_allocator] //~ ERROR: attribute is an experimental feature
 
-#![crate_type = "dylib"]
+fn main() {}
 
-pub fn foo() {}
diff --git a/src/test/compile-fail/auxiliary/allocator1.rs b/src/test/compile-fail/feature-gate-global_allocator.rs
similarity index 70%
rename from src/test/compile-fail/auxiliary/allocator1.rs
rename to src/test/compile-fail/feature-gate-global_allocator.rs
index b24784838d00b..ff3c342f9e003 100644
--- a/src/test/compile-fail/auxiliary/allocator1.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,9 +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;
 
-#![feature(allocator)]
-#![allocator]
-#![crate_type = "rlib"]
-#![no_std]
+fn main() {}
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/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-default.rs b/src/test/run-pass/allocator-default.rs
deleted file mode 100644
index 0a02e8072b9b3..0000000000000
--- a/src/test/run-pass/allocator-default.rs
+++ /dev/null
@@ -1,19 +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.
-
-#![feature(alloc_jemalloc)]
-
-#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-          target_os = "macos"))]
-extern crate alloc_jemalloc;
-
-fn main() {
-    println!("{:?}", Box::new(3));
-}
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/run-pass/allocator/auxiliary/custom-as-global.rs b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs
new file mode 100644
index 0000000000000..538f36faadf2c
--- /dev/null
+++ b/src/test/run-pass/allocator/auxiliary/custom-as-global.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.
+
+// no-prefer-dynamic
+
+#![feature(global_allocator)]
+#![crate_type = "rlib"]
+
+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/needs_allocator.rs b/src/test/run-pass/allocator/auxiliary/helper.rs
similarity index 77%
rename from src/test/compile-fail/auxiliary/needs_allocator.rs
rename to src/test/run-pass/allocator/auxiliary/helper.rs
index 5100316042732..e75a432710df2 100644
--- a/src/test/compile-fail/auxiliary/needs_allocator.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(needs_allocator)]
-#![no_std]
-#![needs_allocator]
 #![crate_type = "rlib"]
+
+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/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 { }

From f668999153d78903658b6937a099819e0b634a06 Mon Sep 17 00:00:00 2001
From: "Zack M. Davis" <code@zackmdavis.net>
Date: Mon, 3 Jul 2017 11:19:51 -0700
Subject: [PATCH 52/52] use field init shorthand in src/librustc

The field init shorthand syntax was stabilized in 1.17.0 (aebd94f); we
are now free to use it in the compiler.
---
 src/librustc/cfg/construct.rs                 |  12 +-
 src/librustc/dep_graph/dep_tracking_map.rs    |   2 +-
 src/librustc/dep_graph/query.rs               |   4 +-
 src/librustc/dep_graph/shadow.rs              |   2 +-
 src/librustc/dep_graph/thread.rs              |   2 +-
 src/librustc/hir/lowering.rs                  | 106 +++++++++---------
 src/librustc/hir/map/blocks.rs                |  14 +--
 src/librustc/hir/map/collector.rs             |   2 +-
 src/librustc/hir/map/def_collector.rs         |   6 +-
 src/librustc/hir/map/definitions.rs           |   8 +-
 src/librustc/hir/map/hir_id_validator.rs      |   4 +-
 src/librustc/hir/map/mod.rs                   |   8 +-
 src/librustc/hir/mod.rs                       |   2 +-
 src/librustc/hir/print.rs                     |   4 +-
 src/librustc/ich/caching_codemap_view.rs      |   2 +-
 src/librustc/ich/hcx.rs                       |   4 +-
 src/librustc/infer/combine.rs                 |   2 +-
 src/librustc/infer/freshen.rs                 |   2 +-
 src/librustc/infer/fudge.rs                   |   2 +-
 src/librustc/infer/higher_ranked/mod.rs       |   2 +-
 src/librustc/infer/mod.rs                     |  18 +--
 src/librustc/infer/region_inference/mod.rs    |  12 +-
 src/librustc/infer/type_variable.rs           |   6 +-
 src/librustc/lint/context.rs                  |  14 +--
 src/librustc/lint/mod.rs                      |   2 +-
 src/librustc/middle/dataflow.rs               |  16 +--
 src/librustc/middle/dead.rs                   |   8 +-
 src/librustc/middle/effect.rs                 |   2 +-
 src/librustc/middle/entry.rs                  |   2 +-
 src/librustc/middle/intrinsicck.rs            |   2 +-
 src/librustc/middle/lang_items.rs             |   6 +-
 src/librustc/middle/liveness.rs               |  10 +-
 src/librustc/middle/mem_categorization.rs     |  20 ++--
 src/librustc/middle/reachable.rs              |   8 +-
 src/librustc/middle/resolve_lifetime.rs       |  20 ++--
 src/librustc/middle/stability.rs              |  12 +-
 src/librustc/mir/mod.rs                       |  58 +++++-----
 src/librustc/mir/tcx.rs                       |  10 +-
 src/librustc/mir/traversal.rs                 |  10 +-
 src/librustc/session/code_stats.rs            |   4 +-
 src/librustc/session/config.rs                |  40 +++----
 src/librustc/session/filesearch.rs            |   8 +-
 src/librustc/session/mod.rs                   |  22 ++--
 src/librustc/traits/coherence.rs              |   4 +-
 src/librustc/traits/fulfill.rs                |  10 +-
 src/librustc/traits/mod.rs                    |   2 +-
 src/librustc/traits/project.rs                |  20 ++--
 src/librustc/traits/select.rs                 |  20 ++--
 src/librustc/traits/structural_impls.rs       |  32 +++---
 src/librustc/traits/util.rs                   |  12 +-
 src/librustc/ty/context.rs                    |  22 ++--
 src/librustc/ty/fold.rs                       |  12 +-
 .../ty/inhabitedness/def_id_forest.rs         |   2 +-
 src/librustc/ty/item_path.rs                  |   2 +-
 src/librustc/ty/layout.rs                     |  34 +++---
 src/librustc/ty/maps.rs                       |   2 +-
 src/librustc/ty/mod.rs                        |  24 ++--
 src/librustc/ty/relate.rs                     |   8 +-
 src/librustc/ty/structural_impls.rs           |  24 ++--
 src/librustc/ty/sty.rs                        |   4 +-
 src/librustc/ty/subst.rs                      |   6 +-
 src/librustc/ty/wf.rs                         |   8 +-
 62 files changed, 374 insertions(+), 374 deletions(-)

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/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/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/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 77b4c977d289e..2238e464cbcd5 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -383,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);
 
@@ -397,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/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 e6dc5da969a88..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);
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 39a719faa123e..fe6b24f3e1f2a 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -485,7 +485,7 @@ impl Session {
 
         *incr_comp_session = IncrCompSession::Active {
             session_directory: session_dir,
-            lock_file: lock_file,
+            lock_file,
         };
     }
 
@@ -515,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,
         };
     }
 
@@ -695,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()),
@@ -733,10 +733,10 @@ 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
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);