From dad587bc7dc7099e3f4c7f04f149c23b9ea7ed84 Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Sun, 13 Aug 2017 18:04:57 +0200
Subject: [PATCH 01/13] Implemented span expansion info encoding in metadata.

This change adds an encoded version of hygiene related datastructures to
the metadata of a crate. It is then decoded on-demand when spans and AST
items from a foreign crate are accessed. Some changes might still be
necessary to implement the correct behaviour, however.
---
 src/doc/book                                  |   2 +-
 src/doc/nomicon                               |   2 +-
 src/doc/reference                             |   2 +-
 src/libcompiler_builtins                      |   2 +-
 src/liblibc                                   |   2 +-
 src/librustc_metadata/creader.rs              |   1 +
 src/librustc_metadata/cstore.rs               |   4 +-
 src/librustc_metadata/decoder.rs              |  50 ++++++-
 src/librustc_metadata/encoder.rs              |  14 +-
 src/librustc_metadata/schema.rs               |   3 +-
 src/libsyntax_pos/hygiene.rs                  | 124 +++++++++++++++---
 src/llvm                                      |   2 +-
 .../auxiliary/macro_spans_lib.rs              |  25 ++++
 src/test/compile-fail-fulldeps/macro-spans.rs |  18 +++
 src/tools/cargo                               |   2 +-
 src/tools/rls                                 |   2 +-
 src/tools/rust-installer                      |   2 +-
 17 files changed, 226 insertions(+), 31 deletions(-)
 create mode 100644 src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs
 create mode 100644 src/test/compile-fail-fulldeps/macro-spans.rs

diff --git a/src/doc/book b/src/doc/book
index 08e79609ce885..d09c9e8144ed3 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 08e79609ce88583fa7286157dfe497486a09fabe
+Subproject commit d09c9e8144ed32170b7596abb145ade8b097acaf
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 0ee3f7265e9d0..a4322ccb289a4 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 0ee3f7265e9d09746d901cef6f1f300baff1d923
+Subproject commit a4322ccb289a43cc238d4536982f184a3eec9ba7
diff --git a/src/doc/reference b/src/doc/reference
index 36adc6ae504c6..1abfbaa70313f 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 36adc6ae504c6e0343ab5d7b3871f0a2a71236da
+Subproject commit 1abfbaa70313fdf527cf799ffd9b9a096a62105c
diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins
index 0b9844764ea1f..6b9281d2b2f0e 160000
--- a/src/libcompiler_builtins
+++ b/src/libcompiler_builtins
@@ -1 +1 @@
-Subproject commit 0b9844764ea1f99ea11a7917a4f3ba7fd2db775c
+Subproject commit 6b9281d2b2f0ebb94838814b1e8ace2de4b7035b
diff --git a/src/liblibc b/src/liblibc
index 44e4018e1a377..2a5b50b7f7f53 160000
--- a/src/liblibc
+++ b/src/liblibc
@@ -1 +1 @@
-Subproject commit 44e4018e1a37716286ec98cb5b7dd7d33ecaf940
+Subproject commit 2a5b50b7f7f539a0fd201331d6c1e0534aa332f5
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 39bdf88925e44..91fdd3390ddd7 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -293,6 +293,7 @@ impl<'a> CrateLoader<'a> {
             // Initialize this with an empty set. The field is populated below
             // after we were able to deserialize its contents.
             dllimport_foreign_items: FxHashSet(),
+            hygiene_data_import_info: RefCell::new(None),
         };
 
         let dllimports: FxHashSet<_> = cmeta
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 9e47e96aee4ef..b9af97c5d9e35 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -27,7 +27,7 @@ use owning_ref::ErasedBoxRef;
 use syntax::{ast, attr};
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
-use syntax_pos;
+use syntax_pos::{self, hygiene};
 
 pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
 pub use rustc::middle::cstore::NativeLibraryKind::*;
@@ -87,6 +87,8 @@ pub struct CrateMetadata {
     pub proc_macros: Option<Vec<(ast::Name, Rc<SyntaxExtension>)>>,
     // Foreign items imported from a dylib (Windows only)
     pub dllimport_foreign_items: FxHashSet<DefIndex>,
+
+    pub hygiene_data_import_info: RefCell<Option<hygiene::ImportedHygieneData>>,
 }
 
 pub struct CStore {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 65cf15e5a0ec7..1c7059343dc0c 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -45,7 +45,8 @@ use syntax::ast::{self, Ident};
 use syntax::codemap;
 use syntax::symbol::{InternedString, Symbol};
 use syntax::ext::base::MacroKind;
-use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION};
+use syntax_pos::{self, Span, SyntaxContext, BytePos, Pos, DUMMY_SP};
+use syntax_pos::hygiene;
 
 pub struct DecodeContext<'a, 'tcx: 'a> {
     opaque: opaque::Decoder<'a>,
@@ -237,15 +238,42 @@ impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> SpecializedDecoder<hygiene::Mark> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<hygiene::Mark, Self::Error> {
+        let mark = u32::decode(self)?;
+        if self.cdata().hygiene_data_import_info.borrow().is_some() && mark != 0  {
+            let imported_hygiene = self.cdata().imported_hygiene_data();
+
+            Ok(hygiene::Mark::from_u32(mark + imported_hygiene.mark_translation_offset))
+        } else {
+            Ok(hygiene::Mark::from_u32(mark))
+        }
+    }
+}
+
+impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
+        let ctxt = u32::decode(self)?;
+        if self.cdata().hygiene_data_import_info.borrow().is_some() && ctxt != 0 {
+            let imported_hygiene = self.cdata().imported_hygiene_data();
+
+            Ok(SyntaxContext::from_u32(ctxt + imported_hygiene.ctxt_translation_offset))
+        } else {
+            Ok(SyntaxContext::from_u32(ctxt))
+        }
+    }
+}
+
 impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
         let lo = BytePos::decode(self)?;
         let hi = BytePos::decode(self)?;
+        let ctxt = SyntaxContext::decode(self)?;
 
         let sess = if let Some(sess) = self.sess {
             sess
         } else {
-            return Ok(Span::new(lo, hi, NO_EXPANSION));
+            return Ok(Span { lo, hi, ctxt });
         };
 
         let (lo, hi) = if lo > hi {
@@ -292,7 +320,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
         let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos;
         let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos;
 
-        Ok(Span::new(lo, hi, NO_EXPANSION))
+        Ok(Span::new(lo, hi, ctxt))
     }
 }
 
@@ -1224,4 +1252,20 @@ impl<'a, 'tcx> CrateMetadata {
         *self.codemap_import_info.borrow_mut() = imported_filemaps;
         self.codemap_import_info.borrow()
     }
+
+    pub fn imported_hygiene_data(&'a self) -> Ref<'a, hygiene::ImportedHygieneData> {
+        {
+            let hygiene_data = self.hygiene_data_import_info.borrow();
+            if hygiene_data.is_some() {
+                return Ref::map(hygiene_data, |d| d.as_ref().unwrap());
+            }
+        }
+
+        let external_hygiene_data = self.root.hygiene_data.decode(self);
+
+        // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
+        *self.hygiene_data_import_info.borrow_mut() =
+            Some(hygiene::extend_hygiene_data(external_hygiene_data));
+        Ref::map(self.hygiene_data_import_info.borrow(), |d| d.as_ref().unwrap())
+    }
 }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 6b49be3e12192..5d6c6075d5b74 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -42,7 +42,7 @@ use syntax::ast::{self, CRATE_NODE_ID};
 use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
-use syntax_pos;
+use syntax_pos::{self, hygiene};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -323,6 +323,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_seq_ref(adapted.iter().map(|rc| &**rc))
     }
 
+    fn encode_hygiene_data(&mut self) -> Lazy<hygiene::HygieneData> {
+        hygiene::HygieneData::safe_with(|data| self.lazy(data))
+    }
+
     fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
         let mut i = self.position();
 
@@ -367,6 +371,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let codemap = self.encode_codemap();
         let codemap_bytes = self.position() - i;
 
+        // Encode hygiene data
+        i = self.position();
+        let hygiene_data = self.encode_hygiene_data();
+        let hygiene_data_bytes = self.position() - i;
+
         // Encode DefPathTable
         i = self.position();
         let def_path_table = self.encode_def_path_table();
@@ -421,13 +430,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             } else {
                 None
             },
-
             crate_deps,
             dylib_dependency_formats,
             lang_items,
             lang_items_missing,
             native_libraries,
             codemap,
+            hygiene_data,
             def_path_table,
             impls,
             exported_symbols,
@@ -456,6 +465,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             println!("         codemap bytes: {}", codemap_bytes);
             println!("            impl bytes: {}", impl_bytes);
             println!("    exp. symbols bytes: {}", exported_symbols_bytes);
+            println!("    hygiene data bytes: {}", hygiene_data_bytes);
             println!("  def-path table bytes: {}", def_path_table_bytes);
             println!("            item bytes: {}", item_bytes);
             println!("           index bytes: {}", index_bytes);
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index dad0d26d2715d..abccc50db8446 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -24,7 +24,7 @@ use rustc_back::PanicStrategy;
 use rustc_serialize as serialize;
 use syntax::{ast, attr};
 use syntax::symbol::Symbol;
-use syntax_pos::{self, Span};
+use syntax_pos::{self, hygiene, Span};
 
 use std::marker::PhantomData;
 use std::mem;
@@ -204,6 +204,7 @@ pub struct CrateRoot {
     pub lang_items_missing: LazySeq<lang_items::LangItem>,
     pub native_libraries: LazySeq<NativeLibrary>,
     pub codemap: LazySeq<syntax_pos::FileMap>,
+    pub hygiene_data: Lazy<hygiene::HygieneData>,
     pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
     pub impls: LazySeq<TraitImpls>,
     pub exported_symbols: LazySeq<DefIndex>,
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 4790fa0a7edc2..72261452cbd72 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -18,16 +18,16 @@
 use Span;
 use symbol::{Ident, Symbol};
 
-use serialize::{Encodable, Decodable, Encoder, Decoder};
+use serialize::{Decoder, UseSpecializedDecodable};
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 
 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
-#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash, RustcEncodable)]
 pub struct SyntaxContext(pub(super) u32);
 
-#[derive(Copy, Clone, Default)]
+#[derive(Copy, Clone, Default, RustcEncodable, RustcDecodable)]
 pub struct SyntaxContextData {
     pub outer_mark: Mark,
     pub prev_ctxt: SyntaxContext,
@@ -35,10 +35,10 @@ pub struct SyntaxContextData {
 }
 
 /// A mark is a unique id associated with a macro expansion.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable)]
 pub struct Mark(u32);
 
-#[derive(Default)]
+#[derive(Default, RustcEncodable, RustcDecodable)]
 struct MarkData {
     parent: Mark,
     modern: bool,
@@ -66,6 +66,14 @@ impl Mark {
         Mark(raw)
     }
 
+    pub fn translate(&self, offset: u32) -> Mark {
+        if self.0 != 0 {
+            Mark(self.0 + offset)
+        } else {
+            Mark(self.0)
+        }
+    }
+
     pub fn expn_info(self) -> Option<ExpnInfo> {
         HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone())
     }
@@ -106,7 +114,8 @@ impl Mark {
     }
 }
 
-struct HygieneData {
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct HygieneData {
     marks: Vec<MarkData>,
     syntax_contexts: Vec<SyntaxContextData>,
     markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
@@ -129,13 +138,98 @@ impl HygieneData {
         }
         HYGIENE_DATA.with(|data| f(&mut *data.borrow_mut()))
     }
+
+    pub fn safe_with<T, F: FnOnce(&HygieneData) -> T>(f: F) -> T {
+        // FIXME(twk): not sure how this would behave...
+        thread_local! {
+            static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
+        }
+        HYGIENE_DATA.with(|data| f(&*data.borrow()))
+    }
 }
 
 pub fn clear_markings() {
     HygieneData::with(|data| data.markings = HashMap::new());
 }
 
+/// Holds information about a HygieneData imported from another crate.
+/// See `imported_hygiene_data()` in `rustc_metadata` for more information.
+pub struct ImportedHygieneData {
+    /// The imported HygieneData's offset in the local HygieneData's marks vector.
+    pub mark_translation_offset: u32,
+    /// The imported HygieneData's offset in the local HygieneData's syntax contexts vector.
+    pub ctxt_translation_offset: u32,
+}
+
+pub fn extend_hygiene_data(extend_with: HygieneData) -> ImportedHygieneData {
+    fn translate_span(span: &Span, offset: u32) -> Span {
+        Span {
+            lo: span.lo,
+            hi: span.hi,
+            ctxt: span.ctxt.translate(offset),
+        }
+    }
+
+    HygieneData::with(move |data| {
+        let mark_offset = data.marks.len() as u32;
+        let ctxt_offset = data.syntax_contexts.len() as u32;
+
+        // skip the default mark, it doesn't need to be translated.
+        for mark_data in extend_with.marks.iter().skip(1) {
+            data.marks.push(MarkData {
+                parent: mark_data.parent.translate(mark_offset),
+                modern: mark_data.modern,
+                expn_info: mark_data.expn_info.as_ref().map(|info| {
+                    ExpnInfo {
+                        call_site: translate_span(&info.call_site, ctxt_offset),
+                        callee: NameAndSpan {
+                            format: info.callee.format.clone(),
+                            allow_internal_unstable: info.callee.allow_internal_unstable,
+                            span:
+                                info.callee.span.map(|span| translate_span(&span, ctxt_offset)),
+                        },
+                    }
+                }),
+            })
+        }
+
+        // skip the default syntax context, it doesn't need to be translated.
+        for ctxt in extend_with.syntax_contexts.iter().skip(1) {
+            data.syntax_contexts.push(SyntaxContextData {
+                outer_mark: ctxt.outer_mark.translate(mark_offset),
+                prev_ctxt: ctxt.prev_ctxt.translate(ctxt_offset),
+                modern: ctxt.modern.translate(ctxt_offset),
+            });
+        }
+
+        // translate markings map and extend the current one
+        for (&(ctxt1, mark), ctxt2) in extend_with.markings.iter() {
+            data.markings.insert((ctxt1.translate(ctxt_offset), mark.translate(mark_offset)),
+                                 ctxt2.translate(ctxt_offset));
+        }
+
+        data.gensym_to_ctxt.extend(extend_with.gensym_to_ctxt);
+
+        ImportedHygieneData {
+            mark_translation_offset: mark_offset,
+            ctxt_translation_offset: ctxt_offset,
+        }
+    })
+}
+
 impl SyntaxContext {
+    pub fn from_u32(raw: u32) -> SyntaxContext {
+        SyntaxContext(raw)
+    }
+
+    pub fn translate(&self, offset: u32) -> SyntaxContext {
+        if self.0 != 0 {
+            SyntaxContext(self.0 + offset)
+        } else {
+            SyntaxContext(self.0)
+        }
+    }
+
     pub const fn empty() -> Self {
         SyntaxContext(0)
     }
@@ -286,7 +380,7 @@ impl fmt::Debug for SyntaxContext {
 }
 
 /// Extra information for tracking spans of macro and syntax sugar expansion
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ExpnInfo {
     /// The location of the actual macro invocation or syntax sugar , e.g.
     /// `let x = foo!();` or `if let Some(y) = x {}`
@@ -302,7 +396,7 @@ pub struct ExpnInfo {
     pub callee: NameAndSpan
 }
 
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct NameAndSpan {
     /// The format with which the macro was invoked.
     pub format: ExpnFormat,
@@ -330,7 +424,7 @@ impl NameAndSpan {
 }
 
 /// The source of expansion.
-#[derive(Clone, Hash, Debug, PartialEq, Eq)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum ExpnFormat {
     /// e.g. #[derive(...)] <item>
     MacroAttribute(Symbol),
@@ -360,15 +454,15 @@ impl CompilerDesugaringKind {
     }
 }
 
-impl Encodable for SyntaxContext {
-    fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
-        Ok(()) // FIXME(jseyfried) intercrate hygiene
+impl UseSpecializedDecodable for SyntaxContext {
+    fn default_decode<D: Decoder>(d: &mut D) -> Result<SyntaxContext, D::Error> {
+        d.read_u32().map(|u| SyntaxContext(u))
     }
 }
 
-impl Decodable for SyntaxContext {
-    fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
-        Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
+impl UseSpecializedDecodable for Mark {
+    fn default_decode<D: Decoder>(d: &mut D) -> Result<Mark, D::Error> {
+        d.read_u32().map(Mark::from_u32)
     }
 }
 
diff --git a/src/llvm b/src/llvm
index c7a16bd57c2a9..d9e7d2696e419 160000
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit c7a16bd57c2a9c643a52f0cebecdaf0b6a996da1
+Subproject commit d9e7d2696e41983b6b5a0b4fac604b4e548a84d3
diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs
new file mode 100644
index 0000000000000..739e37feeae29
--- /dev/null
+++ b/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs
@@ -0,0 +1,25 @@
+// 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.
+
+macro_rules! abc {
+    ($name:ident) => {
+        mod $name {
+            macro_rules! $name {
+                ($name2:ident) => {
+                    struct $name {
+                        $name2: u8,
+                    }
+                }
+            }
+
+            $name!(AStruct)
+        }
+    }
+}
diff --git a/src/test/compile-fail-fulldeps/macro-spans.rs b/src/test/compile-fail-fulldeps/macro-spans.rs
new file mode 100644
index 0000000000000..a3f7a92af719e
--- /dev/null
+++ b/src/test/compile-fail-fulldeps/macro-spans.rs
@@ -0,0 +1,18 @@
+// 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:macro_spans_lib.rs
+
+#[macro_use]
+extern crate macro_spans_lib;
+
+abc!(Name)
+
+fn main() { }
diff --git a/src/tools/cargo b/src/tools/cargo
index e447ac7e94b7f..7704f7b1fd526 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit e447ac7e94b7f56ab13e361f9e324dafe3eb0a34
+Subproject commit 7704f7b1fd52607104cc7fdc435d636c9de1fe90
diff --git a/src/tools/rls b/src/tools/rls
index 93b47d14cef57..5d4bbd9052fe2 160000
--- a/src/tools/rls
+++ b/src/tools/rls
@@ -1 +1 @@
-Subproject commit 93b47d14cef5720bba7cfb4dcb8078fbf1f706c1
+Subproject commit 5d4bbd9052fe2af849a7d017b85df98ad002c20f
diff --git a/src/tools/rust-installer b/src/tools/rust-installer
index 0ddd53c4bc2a7..b4ff403041f17 160000
--- a/src/tools/rust-installer
+++ b/src/tools/rust-installer
@@ -1 +1 @@
-Subproject commit 0ddd53c4bc2a76df565a1c1fc0cc6f19f254b51e
+Subproject commit b4ff403041f17957f735ad750c3241a3a428b9b7

From e6a6c64574dae52fa044934bc8594207f64d5359 Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Sun, 13 Aug 2017 18:09:35 +0200
Subject: [PATCH 02/13] Added an explanation to slightly tricky decoding logic.

---
 src/librustc_metadata/decoder.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 1c7059343dc0c..4353b4fe52965 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -241,6 +241,11 @@ impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedDecoder<hygiene::Mark> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<hygiene::Mark, Self::Error> {
         let mark = u32::decode(self)?;
+        //
+        // We only perform translation if hygiene info is already available and if the
+        // mark actually needs translation. That way we avoid loops (as obtaining hygiene
+        // info for an external crate involves decoding marks) and avoid incorrectly translated
+        // default marks.
         if self.cdata().hygiene_data_import_info.borrow().is_some() && mark != 0  {
             let imported_hygiene = self.cdata().imported_hygiene_data();
 
@@ -254,6 +259,11 @@ impl<'a, 'tcx> SpecializedDecoder<hygiene::Mark> for DecodeContext<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
         let ctxt = u32::decode(self)?;
+
+        // We only perform translation if hygiene info is already available and if the
+        // syntax context actually needs translation. That way we avoid loops (as obtaining
+        // hygiene info for an external crate involves decoding syntax contexts) and avoid
+        // incorrectly translated default contexts.
         if self.cdata().hygiene_data_import_info.borrow().is_some() && ctxt != 0 {
             let imported_hygiene = self.cdata().imported_hygiene_data();
 

From b47a79105c911fd9ac4659bd05d38c719145edda Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Sun, 13 Aug 2017 18:48:23 +0200
Subject: [PATCH 03/13] Fixed build after rebase

---
 src/libsyntax_pos/hygiene.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 72261452cbd72..d1c101eaed5db 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -185,6 +185,7 @@ pub fn extend_hygiene_data(extend_with: HygieneData) -> ImportedHygieneData {
                         callee: NameAndSpan {
                             format: info.callee.format.clone(),
                             allow_internal_unstable: info.callee.allow_internal_unstable,
+                            allow_internal_unsafe: info.callee.allow_internal_unsafe,
                             span:
                                 info.callee.span.map(|span| translate_span(&span, ctxt_offset)),
                         },

From 7bb56bf742655bade24e82a883eecbb475bc86bd Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Mon, 14 Aug 2017 12:59:04 +0200
Subject: [PATCH 04/13] Actually encode syntax context info for spans.

---
 src/librustc_metadata/decoder.rs | 5 ++---
 src/libsyntax_pos/lib.rs         | 6 +++++-
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 4353b4fe52965..f821ccc91f9fb 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -45,8 +45,7 @@ use syntax::ast::{self, Ident};
 use syntax::codemap;
 use syntax::symbol::{InternedString, Symbol};
 use syntax::ext::base::MacroKind;
-use syntax_pos::{self, Span, SyntaxContext, BytePos, Pos, DUMMY_SP};
-use syntax_pos::hygiene;
+use syntax_pos::{self, hygiene, Span, SyntaxContext, BytePos, Pos, DUMMY_SP};
 
 pub struct DecodeContext<'a, 'tcx: 'a> {
     opaque: opaque::Decoder<'a>,
@@ -241,7 +240,7 @@ impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedDecoder<hygiene::Mark> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<hygiene::Mark, Self::Error> {
         let mark = u32::decode(self)?;
-        //
+
         // We only perform translation if hygiene info is already available and if the
         // mark actually needs translation. That way we avoid loops (as obtaining hygiene
         // info for an external crate involves decoding marks) and avoid incorrectly translated
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 2000db9703cf9..9f4172037892d 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -316,13 +316,17 @@ impl Default for Span {
 
 impl serialize::UseSpecializedEncodable for Span {
     fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct("Span", 2, |s| {
+        s.emit_struct("Span", 3, |s| {
             s.emit_struct_field("lo", 0, |s| {
                 self.lo().encode(s)
             })?;
 
             s.emit_struct_field("hi", 1, |s| {
                 self.hi().encode(s)
+            })?;
+
+            s.emit_struct_field("ctxt", 2, |s| {
+                self.ctxt().encode(s)
             })
         })
     }

From 214fb564e0fb917580056bdc5d6a1b55acd4cd5f Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Mon, 14 Aug 2017 16:45:16 +0200
Subject: [PATCH 05/13] Fixed the on-demand decoding mechanism for hygiene
 data.

---
 src/librustc_metadata/creader.rs |  1 +
 src/librustc_metadata/cstore.rs  |  1 +
 src/librustc_metadata/decoder.rs | 18 +++++++-----------
 3 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 91fdd3390ddd7..2cf5c92ea6721 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -294,6 +294,7 @@ impl<'a> CrateLoader<'a> {
             // after we were able to deserialize its contents.
             dllimport_foreign_items: FxHashSet(),
             hygiene_data_import_info: RefCell::new(None),
+            hygiene_data_being_decoded: Cell::new(false),
         };
 
         let dllimports: FxHashSet<_> = cmeta
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index b9af97c5d9e35..38578d9c286f9 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -89,6 +89,7 @@ pub struct CrateMetadata {
     pub dllimport_foreign_items: FxHashSet<DefIndex>,
 
     pub hygiene_data_import_info: RefCell<Option<hygiene::ImportedHygieneData>>,
+    pub hygiene_data_being_decoded: Cell<bool>,
 }
 
 pub struct CStore {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index f821ccc91f9fb..ef56703f68cc0 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -241,11 +241,7 @@ impl<'a, 'tcx> SpecializedDecoder<hygiene::Mark> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<hygiene::Mark, Self::Error> {
         let mark = u32::decode(self)?;
 
-        // We only perform translation if hygiene info is already available and if the
-        // mark actually needs translation. That way we avoid loops (as obtaining hygiene
-        // info for an external crate involves decoding marks) and avoid incorrectly translated
-        // default marks.
-        if self.cdata().hygiene_data_import_info.borrow().is_some() && mark != 0  {
+        if !self.cdata().hygiene_data_being_decoded.get() && mark != 0  {
             let imported_hygiene = self.cdata().imported_hygiene_data();
 
             Ok(hygiene::Mark::from_u32(mark + imported_hygiene.mark_translation_offset))
@@ -259,11 +255,7 @@ impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
         let ctxt = u32::decode(self)?;
 
-        // We only perform translation if hygiene info is already available and if the
-        // syntax context actually needs translation. That way we avoid loops (as obtaining
-        // hygiene info for an external crate involves decoding syntax contexts) and avoid
-        // incorrectly translated default contexts.
-        if self.cdata().hygiene_data_import_info.borrow().is_some() && ctxt != 0 {
+        if !self.cdata().hygiene_data_being_decoded.get() && ctxt != 0 {
             let imported_hygiene = self.cdata().imported_hygiene_data();
 
             Ok(SyntaxContext::from_u32(ctxt + imported_hygiene.ctxt_translation_offset))
@@ -1270,11 +1262,15 @@ impl<'a, 'tcx> CrateMetadata {
             }
         }
 
+        self.hygiene_data_being_decoded.set(true);
+
         let external_hygiene_data = self.root.hygiene_data.decode(self);
 
         // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
         *self.hygiene_data_import_info.borrow_mut() =
             Some(hygiene::extend_hygiene_data(external_hygiene_data));
-        Ref::map(self.hygiene_data_import_info.borrow(), |d| d.as_ref().unwrap())
+        self.hygiene_data_being_decoded.set(false);
+
+        Ref::map(self.hygiene_data_import_info.borrow(), |d| d.as_ref().unwrap());
     }
 }

From 64934bab20b25ea6f58724b6c90de47c63de56cc Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Tue, 15 Aug 2017 22:30:06 +0200
Subject: [PATCH 06/13] Fixed one possible error source when encoding hygiene
 metadata.

Sadly, this isn't the reason the tests fail.
---
 src/librustc/middle/cstore.rs        | 3 +++
 src/librustc_metadata/cstore_impl.rs | 6 ++++++
 src/librustc_metadata/decoder.rs     | 2 +-
 src/librustc_metadata/encoder.rs     | 1 +
 4 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index a97bfa0536987..d7540aed5a024 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -253,6 +253,8 @@ pub struct ExternBodyNestedBodies {
 pub trait CrateStore {
     fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
 
+    fn ensure_hygiene_data_loaded(&self);
+
     // access to the metadata loader
     fn metadata_loader(&self) -> &MetadataLoader;
 
@@ -325,6 +327,7 @@ pub struct DummyCrateStore;
 impl CrateStore for DummyCrateStore {
     fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>
         { bug!("crate_data_as_rc_any") }
+    fn ensure_hygiene_data_loaded(&self) { bug!("ensure_hygiene_data_loaded") }
     // item info
     fn visibility_untracked(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
     fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 8eacc21ab003b..3d67868f36618 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -350,6 +350,12 @@ impl CrateStore for cstore::CStore {
         self.get_crate_data(krate)
     }
 
+    fn ensure_hygiene_data_loaded(&self) {
+        self.iter_crate_data(|_, metadata| {
+            (*metadata).imported_hygiene_data();
+        });
+    }
+
     fn metadata_loader(&self) -> &MetadataLoader {
         &*self.metadata_loader
     }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index ef56703f68cc0..5a80f6764d185 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -1271,6 +1271,6 @@ impl<'a, 'tcx> CrateMetadata {
             Some(hygiene::extend_hygiene_data(external_hygiene_data));
         self.hygiene_data_being_decoded.set(false);
 
-        Ref::map(self.hygiene_data_import_info.borrow(), |d| d.as_ref().unwrap());
+        Ref::map(self.hygiene_data_import_info.borrow(), |d| d.as_ref().unwrap())
     }
 }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 5d6c6075d5b74..0010f7638e8b2 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -324,6 +324,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_hygiene_data(&mut self) -> Lazy<hygiene::HygieneData> {
+        self.tcx.sess.cstore.ensure_hygiene_data_loaded();
         hygiene::HygieneData::safe_with(|data| self.lazy(data))
     }
 

From 754bf65a3579750ec8227f155e97480af5d67c2c Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Thu, 17 Aug 2017 11:26:41 +0200
Subject: [PATCH 07/13] Fixed broken functionality.

However, now that it behaves as expected, the memory usage is
unacceptably high. A solution would be more lazyness during encoding or
a pruning scheme.
---
 src/libsyntax_pos/hygiene.rs | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index d1c101eaed5db..d9d09ca467a68 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -122,6 +122,10 @@ pub struct HygieneData {
     gensym_to_ctxt: HashMap<Symbol, SyntaxContext>,
 }
 
+thread_local! {
+    static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
+}
+
 impl HygieneData {
     fn new() -> Self {
         HygieneData {
@@ -133,17 +137,10 @@ impl HygieneData {
     }
 
     fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
-        thread_local! {
-            static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
-        }
         HYGIENE_DATA.with(|data| f(&mut *data.borrow_mut()))
     }
 
     pub fn safe_with<T, F: FnOnce(&HygieneData) -> T>(f: F) -> T {
-        // FIXME(twk): not sure how this would behave...
-        thread_local! {
-            static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
-        }
         HYGIENE_DATA.with(|data| f(&*data.borrow()))
     }
 }

From b653026401367917cbab0cfec87b3adfc58482ee Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Fri, 18 Aug 2017 13:18:13 +0200
Subject: [PATCH 08/13] Implemented first steps of a new, leaner hygiene data
 encoding scheme.

---
 src/librustc_metadata/decoder.rs |   4 +-
 src/librustc_metadata/encoder.rs |  51 +++++--
 src/librustc_metadata/schema.rs  |   2 +-
 src/libsyntax_pos/hygiene.rs     | 249 +++++++++++++++++++++++++------
 4 files changed, 243 insertions(+), 63 deletions(-)

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 5a80f6764d185..1d7ab542cdc09 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -244,7 +244,7 @@ impl<'a, 'tcx> SpecializedDecoder<hygiene::Mark> for DecodeContext<'a, 'tcx> {
         if !self.cdata().hygiene_data_being_decoded.get() && mark != 0  {
             let imported_hygiene = self.cdata().imported_hygiene_data();
 
-            Ok(hygiene::Mark::from_u32(mark + imported_hygiene.mark_translation_offset))
+            Ok(imported_hygiene.translate_mark(hygiene::Mark::from_u32(mark)))
         } else {
             Ok(hygiene::Mark::from_u32(mark))
         }
@@ -258,7 +258,7 @@ impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for DecodeContext<'a, 'tcx> {
         if !self.cdata().hygiene_data_being_decoded.get() && ctxt != 0 {
             let imported_hygiene = self.cdata().imported_hygiene_data();
 
-            Ok(SyntaxContext::from_u32(ctxt + imported_hygiene.ctxt_translation_offset))
+            Ok(imported_hygiene.translate_ctxt(SyntaxContext::from_u32(ctxt)))
         } else {
             Ok(SyntaxContext::from_u32(ctxt))
         }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 0010f7638e8b2..08a968c1b4c78 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -29,7 +29,7 @@ use rustc::ty::{self, Ty, TyCtxt, ReprOptions};
 use rustc::session::config::{self, CrateTypeProcMacro};
 use rustc::util::nodemap::{FxHashMap, NodeSet};
 
-use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
+use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, UseSpecializedEncodable, opaque};
 
 use std::hash::Hash;
 use std::intrinsics;
@@ -61,6 +61,13 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
 
     pub metadata_hashes: EncodedMetadataHashes,
     pub compute_ich: bool,
+    // We need to encode hygiene info after all spans and possibly other data structures
+    // that reference it have been encoded already, since we only encode those elements of it
+    // that are actually used to avoid excessive memory usage. Thus, we need to keep track of
+    // whether we already encoded the hygiene info (and thus committed to a specific set of
+    // information to encode) to make sure we can catch bugs introduced by further changes
+    // quickly.
+    already_encoded_hygiene_data: bool,
 }
 
 macro_rules! encoder_methods {
@@ -136,6 +143,26 @@ impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext
     }
 }
 
+impl<'a, 'tcx> SpecializedEncoder<hygiene::SyntaxContext> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, ctxt: &hygiene::SyntaxContext) -> Result<(), Self::Error> {
+        if self.already_encoded_hygiene_data {
+            bug!("trying to encode syntax context `{:?}` after encoding hygiene data!", ctxt);
+        } else {
+            ctxt.default_encode(self)
+        }
+    }
+}
+
+impl<'a, 'tcx> SpecializedEncoder<hygiene::Mark> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, mark: &hygiene::Mark) -> Result<(), Self::Error> {
+        if self.already_encoded_hygiene_data {
+            bug!("trying to encode mark `{:?}` after encoding hygiene data!", mark);
+        } else {
+            mark.default_encode(self)
+        }
+    }
+}
+
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     pub fn position(&self) -> usize {
@@ -323,9 +350,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_seq_ref(adapted.iter().map(|rc| &**rc))
     }
 
-    fn encode_hygiene_data(&mut self) -> Lazy<hygiene::HygieneData> {
-        self.tcx.sess.cstore.ensure_hygiene_data_loaded();
-        hygiene::HygieneData::safe_with(|data| self.lazy(data))
+    fn encode_hygiene_data(&mut self) -> Lazy<hygiene::HygieneDataMap> {
+        // TODO(twk): remove the `ensure_hygiene_data_loaded` method!
+        hygiene::HygieneData::safe_with(|data| self.lazy(&data.to_map()))
     }
 
     fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
@@ -372,11 +399,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let codemap = self.encode_codemap();
         let codemap_bytes = self.position() - i;
 
-        // Encode hygiene data
-        i = self.position();
-        let hygiene_data = self.encode_hygiene_data();
-        let hygiene_data_bytes = self.position() - i;
-
         // Encode DefPathTable
         i = self.position();
         let def_path_table = self.encode_def_path_table();
@@ -407,6 +429,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let index = items.write_index(&mut self.opaque.cursor);
         let index_bytes = self.position() - i;
 
+        // Encode hygiene data
+        i = self.position();
+        let hygiene_data = self.encode_hygiene_data();
+        let hygiene_data_bytes = self.position() - i;
+        self.already_encoded_hygiene_data = true;
+
         let tcx = self.tcx;
         let link_meta = self.link_meta;
         let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
@@ -437,11 +465,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             lang_items_missing,
             native_libraries,
             codemap,
-            hygiene_data,
             def_path_table,
             impls,
             exported_symbols,
             index,
+            hygiene_data,
         });
 
         let total_bytes = self.position();
@@ -466,10 +494,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             println!("         codemap bytes: {}", codemap_bytes);
             println!("            impl bytes: {}", impl_bytes);
             println!("    exp. symbols bytes: {}", exported_symbols_bytes);
-            println!("    hygiene data bytes: {}", hygiene_data_bytes);
             println!("  def-path table bytes: {}", def_path_table_bytes);
             println!("            item bytes: {}", item_bytes);
             println!("           index bytes: {}", index_bytes);
+            println!("    hygiene data bytes: {}", hygiene_data_bytes);
             println!("            zero bytes: {}", zero_bytes);
             println!("           total bytes: {}", total_bytes);
         }
@@ -1689,6 +1717,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             predicate_shorthands: Default::default(),
             metadata_hashes: EncodedMetadataHashes::new(),
             compute_ich,
+            already_encoded_hygiene_data: false,
         };
 
         // Encode the rustc version string in a predictable location.
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index abccc50db8446..26e90913d0a9e 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -204,11 +204,11 @@ pub struct CrateRoot {
     pub lang_items_missing: LazySeq<lang_items::LangItem>,
     pub native_libraries: LazySeq<NativeLibrary>,
     pub codemap: LazySeq<syntax_pos::FileMap>,
-    pub hygiene_data: Lazy<hygiene::HygieneData>,
     pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
     pub impls: LazySeq<TraitImpls>,
     pub exported_symbols: LazySeq<DefIndex>,
     pub index: LazySeq<index::Index>,
+    pub hygiene_data: Lazy<hygiene::HygieneDataMap>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index d9d09ca467a68..3d766279a930f 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -18,13 +18,13 @@
 use Span;
 use symbol::{Ident, Symbol};
 
-use serialize::{Decoder, UseSpecializedDecodable};
+use serialize::{Decoder, Encoder, UseSpecializedDecodable, UseSpecializedEncodable};
 use std::cell::RefCell;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet, VecDeque};
 use std::fmt;
 
 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
-#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash, RustcEncodable)]
+#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
 pub struct SyntaxContext(pub(super) u32);
 
 #[derive(Copy, Clone, Default, RustcEncodable, RustcDecodable)]
@@ -35,10 +35,10 @@ pub struct SyntaxContextData {
 }
 
 /// A mark is a unique id associated with a macro expansion.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
 pub struct Mark(u32);
 
-#[derive(Default, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Default, RustcEncodable, RustcDecodable)]
 struct MarkData {
     parent: Mark,
     modern: bool,
@@ -114,12 +114,20 @@ impl Mark {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
 pub struct HygieneData {
     marks: Vec<MarkData>,
     syntax_contexts: Vec<SyntaxContextData>,
     markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
     gensym_to_ctxt: HashMap<Symbol, SyntaxContext>,
+    used_marks: Vec<Mark>,
+    used_syntax_contexts: Vec<SyntaxContext>,
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct HygieneDataMap {
+    marks: HashMap<Mark, MarkData>,
+    syntax_contexts: HashMap<SyntaxContext, SyntaxContextData>,
+    gensym_to_ctxt: HashMap<Symbol, SyntaxContext>,
 }
 
 thread_local! {
@@ -133,6 +141,8 @@ impl HygieneData {
             syntax_contexts: vec![SyntaxContextData::default()],
             markings: HashMap::new(),
             gensym_to_ctxt: HashMap::new(),
+            used_marks: Vec::new(),
+            used_syntax_contexts: Vec::new(),
         }
     }
 
@@ -143,75 +153,202 @@ impl HygieneData {
     pub fn safe_with<T, F: FnOnce(&HygieneData) -> T>(f: F) -> T {
         HYGIENE_DATA.with(|data| f(&*data.borrow()))
     }
+
+    pub fn to_map(&self) -> HygieneDataMap {
+        let mut marks = HashMap::new();
+        let mut syntax_contexts = HashMap::new();
+
+        let mut mark_queue: VecDeque<_> = self.used_marks.iter().cloned().collect();
+        let mut ctxt_queue: VecDeque<_> = self.used_syntax_contexts.iter().cloned().collect();
+        ctxt_queue.extend(self.gensym_to_ctxt.values());
+
+        let gensym_to_ctxt = self.gensym_to_ctxt.clone();
+
+        let mut visited_marks = HashSet::new();
+        let mut visited_ctxts = HashSet::new();
+
+        loop {
+            let next_mark = mark_queue.pop_front().and_then(|mark|
+                // skip default mark and already visited marks
+                if visited_marks.contains(&mark) || mark.0 == 0 {
+                    None
+                } else {
+                    visited_marks.insert(mark);
+                    Some(mark)
+                });
+            let next_ctxt = ctxt_queue.pop_front().and_then(|ctxt|
+                // skip default context and already visited contexts
+                if visited_ctxts.contains(&ctxt) || ctxt.0 == 0 {
+                    None
+                } else {
+                    visited_ctxts.insert(ctxt);
+                    Some(ctxt)
+                });
+
+            if next_mark.is_none() && next_ctxt.is_none() {
+                break;
+            }
+
+            if let Some(mark) = next_mark {
+                let data = &self.marks[mark.0 as usize];
+
+                mark_queue.push_back(data.parent);
+                if let Some(ref info) = data.expn_info {
+                    ctxt_queue.push_back(info.call_site.ctxt);
+
+                    if let Some(span) = info.callee.span {
+                        ctxt_queue.push_back(span.ctxt);
+                    }
+                }
+
+                marks.insert(mark, data.clone());
+            }
+
+            if let Some(ctxt) = next_ctxt {
+                let data = self.syntax_contexts[ctxt.0 as usize];
+
+                mark_queue.push_back(data.outer_mark);
+                ctxt_queue.push_back(data.prev_ctxt);
+                ctxt_queue.push_back(data.modern);
+
+                syntax_contexts.insert(ctxt, data);
+            }
+        }
+
+        HygieneDataMap {
+            marks,
+            syntax_contexts,
+            gensym_to_ctxt,
+        }
+    }
 }
 
 pub fn clear_markings() {
     HygieneData::with(|data| data.markings = HashMap::new());
 }
 
+fn register_mark_use(mark: Mark) {
+    HygieneData::with(|data| if !data.used_marks.contains(&mark) {
+        data.used_marks.push(mark);
+    });
+}
+
+fn register_syntax_context_use(ctxt: SyntaxContext) {
+    HygieneData::with(|data| if !data.used_syntax_contexts.contains(&ctxt) {
+        data.used_syntax_contexts.push(ctxt)
+    });
+}
+
 /// Holds information about a HygieneData imported from another crate.
 /// See `imported_hygiene_data()` in `rustc_metadata` for more information.
+#[derive(Default)]
 pub struct ImportedHygieneData {
-    /// The imported HygieneData's offset in the local HygieneData's marks vector.
-    pub mark_translation_offset: u32,
-    /// The imported HygieneData's offset in the local HygieneData's syntax contexts vector.
-    pub ctxt_translation_offset: u32,
+    /// Map an external crate's syntax contexts to the current crate's.
+    ctxt_map: HashMap<SyntaxContext, SyntaxContext>,
+    /// Map an external crate's marks to the current crate's.
+    mark_map: HashMap<Mark, Mark>,
 }
 
-pub fn extend_hygiene_data(extend_with: HygieneData) -> ImportedHygieneData {
-    fn translate_span(span: &Span, offset: u32) -> Span {
+impl ImportedHygieneData {
+    fn insert_ctxt(&mut self, external: SyntaxContext, target: SyntaxContext) {
+        assert!(!self.ctxt_map.contains_key(&external));
+        self.ctxt_map.insert(external, target);
+    }
+
+    fn insert_mark(&mut self, external: Mark, target: Mark) {
+        assert!(!self.mark_map.contains_key(&external));
+        self.mark_map.insert(external, target);
+    }
+
+    pub fn translate_ctxt(&self, external: SyntaxContext) -> SyntaxContext {
+        self.ctxt_map[&external]
+    }
+
+    pub fn translate_mark(&self, external: Mark) -> Mark {
+        self.mark_map[&external]
+    }
+
+    pub fn translate_span(&self, external: Span) -> Span {
         Span {
-            lo: span.lo,
-            hi: span.hi,
-            ctxt: span.ctxt.translate(offset),
+            lo: external.lo,
+            hi: external.hi,
+            ctxt: self.ctxt_map[&external.ctxt],
+        }
+    }
+
+    fn translate_mark_data(&self, data: MarkData) -> MarkData {
+        MarkData {
+            parent: self.translate_mark(data.parent),
+            modern: data.modern,
+            expn_info: data.expn_info.as_ref().map(|info| {
+                ExpnInfo {
+                    call_site: self.translate_span(info.call_site),
+                    callee: NameAndSpan {
+                        format: info.callee.format.clone(),
+                        allow_internal_unstable: info.callee.allow_internal_unstable,
+                        allow_internal_unsafe: info.callee.allow_internal_unsafe,
+                        span: info.callee.span.map(|span| self.translate_span(span)),
+                    },
+                }
+            }),
         }
     }
 
+    fn translate_ctxt_data(&self, data: SyntaxContextData) -> SyntaxContextData {
+        SyntaxContextData {
+            outer_mark: self.translate_mark(data.outer_mark),
+            prev_ctxt: self.translate_ctxt(data.prev_ctxt),
+            modern: self.translate_ctxt(data.modern),
+        }
+    }
+}
+
+pub fn extend_hygiene_data(extend_with: HygieneDataMap) -> ImportedHygieneData {
     HygieneData::with(move |data| {
+        let mut imported_map = ImportedHygieneData::default();
         let mark_offset = data.marks.len() as u32;
         let ctxt_offset = data.syntax_contexts.len() as u32;
 
-        // skip the default mark, it doesn't need to be translated.
-        for mark_data in extend_with.marks.iter().skip(1) {
-            data.marks.push(MarkData {
-                parent: mark_data.parent.translate(mark_offset),
-                modern: mark_data.modern,
-                expn_info: mark_data.expn_info.as_ref().map(|info| {
-                    ExpnInfo {
-                        call_site: translate_span(&info.call_site, ctxt_offset),
-                        callee: NameAndSpan {
-                            format: info.callee.format.clone(),
-                            allow_internal_unstable: info.callee.allow_internal_unstable,
-                            allow_internal_unsafe: info.callee.allow_internal_unsafe,
-                            span:
-                                info.callee.span.map(|span| translate_span(&span, ctxt_offset)),
-                        },
-                    }
-                }),
+        let HygieneDataMap {
+            mut marks,
+            mut syntax_contexts,
+            mut gensym_to_ctxt,
+        } = extend_with;
+
+        let marks: Vec<_> = marks
+            .drain()
+            .enumerate()
+            .map(|(index_offset, (mark, data))| {
+                let index_offset = index_offset as u32;
+                imported_map.insert_mark(mark, mark.translate(mark_offset + index_offset));
+                data
             })
-        }
+            .collect();
+
+        let syntax_contexts: Vec<_> = syntax_contexts
+            .drain()
+            .enumerate()
+            .map(|(index_offset, (ctxt, data))| {
+                let index_offset = index_offset as u32;
+                imported_map.insert_ctxt(ctxt, ctxt.translate(ctxt_offset + index_offset));
+                data
+            })
+            .collect();
 
-        // skip the default syntax context, it doesn't need to be translated.
-        for ctxt in extend_with.syntax_contexts.iter().skip(1) {
-            data.syntax_contexts.push(SyntaxContextData {
-                outer_mark: ctxt.outer_mark.translate(mark_offset),
-                prev_ctxt: ctxt.prev_ctxt.translate(ctxt_offset),
-                modern: ctxt.modern.translate(ctxt_offset),
-            });
+        for mark in marks {
+            data.marks.push(imported_map.translate_mark_data(mark));
         }
 
-        // translate markings map and extend the current one
-        for (&(ctxt1, mark), ctxt2) in extend_with.markings.iter() {
-            data.markings.insert((ctxt1.translate(ctxt_offset), mark.translate(mark_offset)),
-                                 ctxt2.translate(ctxt_offset));
+        for ctxt in syntax_contexts {
+            data.syntax_contexts.push(imported_map.translate_ctxt_data(ctxt));
         }
 
-        data.gensym_to_ctxt.extend(extend_with.gensym_to_ctxt);
+        data.gensym_to_ctxt
+            .extend(gensym_to_ctxt
+                        .drain()
+                        .map(|(symbol, ctxt)| (symbol, imported_map.translate_ctxt(ctxt))));
 
-        ImportedHygieneData {
-            mark_translation_offset: mark_offset,
-            ctxt_translation_offset: ctxt_offset,
-        }
+        imported_map
     })
 }
 
@@ -458,12 +595,26 @@ impl UseSpecializedDecodable for SyntaxContext {
     }
 }
 
+impl UseSpecializedEncodable for SyntaxContext {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        register_syntax_context_use(*self);
+        s.emit_u32(self.0)
+    }
+}
+
 impl UseSpecializedDecodable for Mark {
     fn default_decode<D: Decoder>(d: &mut D) -> Result<Mark, D::Error> {
         d.read_u32().map(Mark::from_u32)
     }
 }
 
+impl UseSpecializedEncodable for Mark {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        register_mark_use(*self);
+        s.emit_u32(self.0)
+    }
+}
+
 impl Symbol {
     pub fn from_ident(ident: Ident) -> Symbol {
         HygieneData::with(|data| {

From e3e790a9293180cab97c62b04d9ca4de604ac516 Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Sat, 19 Aug 2017 18:17:48 +0200
Subject: [PATCH 09/13] Fixed on-demand hygiene info encoding.

---
 src/librustc_metadata/decoder.rs |  1 +
 src/librustc_metadata/encoder.rs |  6 ++++--
 src/libsyntax_pos/hygiene.rs     | 25 ++++++++++++++-----------
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 1d7ab542cdc09..2b8599a7988e5 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -1269,6 +1269,7 @@ impl<'a, 'tcx> CrateMetadata {
         // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
         *self.hygiene_data_import_info.borrow_mut() =
             Some(hygiene::extend_hygiene_data(external_hygiene_data));
+
         self.hygiene_data_being_decoded.set(false);
 
         Ref::map(self.hygiene_data_import_info.borrow(), |d| d.as_ref().unwrap())
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 08a968c1b4c78..3c22ae1be8d9e 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -351,8 +351,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_hygiene_data(&mut self) -> Lazy<hygiene::HygieneDataMap> {
-        // TODO(twk): remove the `ensure_hygiene_data_loaded` method!
-        hygiene::HygieneData::safe_with(|data| self.lazy(&data.to_map()))
+        // FIXME(twk): remove the `ensure_hygiene_data_loaded` method
+        // self.tcx.sess.cstore.ensure_hygiene_data_loaded();
+        let data = hygiene::HygieneData::safe_with(|data| data.to_map());
+        self.lazy(&data)
     }
 
     fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 3d766279a930f..a9297e2847e77 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -161,13 +161,12 @@ impl HygieneData {
         let mut mark_queue: VecDeque<_> = self.used_marks.iter().cloned().collect();
         let mut ctxt_queue: VecDeque<_> = self.used_syntax_contexts.iter().cloned().collect();
         ctxt_queue.extend(self.gensym_to_ctxt.values());
-
         let gensym_to_ctxt = self.gensym_to_ctxt.clone();
 
         let mut visited_marks = HashSet::new();
         let mut visited_ctxts = HashSet::new();
 
-        loop {
+        while !(mark_queue.is_empty() && ctxt_queue.is_empty()) {
             let next_mark = mark_queue.pop_front().and_then(|mark|
                 // skip default mark and already visited marks
                 if visited_marks.contains(&mark) || mark.0 == 0 {
@@ -185,10 +184,6 @@ impl HygieneData {
                     Some(ctxt)
                 });
 
-            if next_mark.is_none() && next_ctxt.is_none() {
-                break;
-            }
-
             if let Some(mark) = next_mark {
                 let data = &self.marks[mark.0 as usize];
 
@@ -261,18 +256,26 @@ impl ImportedHygieneData {
     }
 
     pub fn translate_ctxt(&self, external: SyntaxContext) -> SyntaxContext {
-        self.ctxt_map[&external]
+        if external.0 != 0 {
+            self.ctxt_map[&external]
+        } else {
+            external
+        }
     }
 
     pub fn translate_mark(&self, external: Mark) -> Mark {
-        self.mark_map[&external]
+        if external.0 != 0 {
+            self.mark_map[&external]
+        } else {
+            external
+        }
     }
 
     pub fn translate_span(&self, external: Span) -> Span {
         Span {
             lo: external.lo,
             hi: external.hi,
-            ctxt: self.ctxt_map[&external.ctxt],
+            ctxt: self.translate_ctxt(external.ctxt),
         }
     }
 
@@ -320,7 +323,7 @@ pub fn extend_hygiene_data(extend_with: HygieneDataMap) -> ImportedHygieneData {
             .enumerate()
             .map(|(index_offset, (mark, data))| {
                 let index_offset = index_offset as u32;
-                imported_map.insert_mark(mark, mark.translate(mark_offset + index_offset));
+                imported_map.insert_mark(mark, Mark(mark_offset + index_offset));
                 data
             })
             .collect();
@@ -330,7 +333,7 @@ pub fn extend_hygiene_data(extend_with: HygieneDataMap) -> ImportedHygieneData {
             .enumerate()
             .map(|(index_offset, (ctxt, data))| {
                 let index_offset = index_offset as u32;
-                imported_map.insert_ctxt(ctxt, ctxt.translate(ctxt_offset + index_offset));
+                imported_map.insert_ctxt(ctxt, SyntaxContext(ctxt_offset + index_offset));
                 data
             })
             .collect();

From 3927f51def14398f94b29b996431e8242a0978a3 Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Sat, 19 Aug 2017 19:10:00 +0200
Subject: [PATCH 10/13] Added serialization instances after rebase.

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

diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index a9297e2847e77..eabde196f73a0 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -573,7 +573,7 @@ pub enum ExpnFormat {
 }
 
 /// The kind of compiler desugaring.
-#[derive(Clone, Hash, Debug, PartialEq, Eq)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum CompilerDesugaringKind {
     BackArrow,
     DotFill,

From 909808f9d9ea386ddd35430da23c3568de55f6ff Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Sun, 20 Aug 2017 16:26:33 +0200
Subject: [PATCH 11/13] Removed some cruft added for macro expansion
 serialization.

---
 src/librustc/middle/cstore.rs        | 3 ---
 src/librustc_metadata/cstore_impl.rs | 6 ------
 src/librustc_metadata/encoder.rs     | 2 --
 3 files changed, 11 deletions(-)

diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index d7540aed5a024..a97bfa0536987 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -253,8 +253,6 @@ pub struct ExternBodyNestedBodies {
 pub trait CrateStore {
     fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
 
-    fn ensure_hygiene_data_loaded(&self);
-
     // access to the metadata loader
     fn metadata_loader(&self) -> &MetadataLoader;
 
@@ -327,7 +325,6 @@ pub struct DummyCrateStore;
 impl CrateStore for DummyCrateStore {
     fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>
         { bug!("crate_data_as_rc_any") }
-    fn ensure_hygiene_data_loaded(&self) { bug!("ensure_hygiene_data_loaded") }
     // item info
     fn visibility_untracked(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
     fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 3d67868f36618..8eacc21ab003b 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -350,12 +350,6 @@ impl CrateStore for cstore::CStore {
         self.get_crate_data(krate)
     }
 
-    fn ensure_hygiene_data_loaded(&self) {
-        self.iter_crate_data(|_, metadata| {
-            (*metadata).imported_hygiene_data();
-        });
-    }
-
     fn metadata_loader(&self) -> &MetadataLoader {
         &*self.metadata_loader
     }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 3c22ae1be8d9e..41cb54117dbb7 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -351,8 +351,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_hygiene_data(&mut self) -> Lazy<hygiene::HygieneDataMap> {
-        // FIXME(twk): remove the `ensure_hygiene_data_loaded` method
-        // self.tcx.sess.cstore.ensure_hygiene_data_loaded();
         let data = hygiene::HygieneData::safe_with(|data| data.to_map());
         self.lazy(&data)
     }

From 6cb141af6f7426e15d04b4dc77c9238a8e0ab9bb Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Wed, 11 Oct 2017 20:20:34 +0200
Subject: [PATCH 12/13] Fixed submodules. Kinda.

---
 src/doc/book             | 2 +-
 src/doc/nomicon          | 2 +-
 src/doc/reference        | 2 +-
 src/libcompiler_builtins | 2 +-
 src/liblibc              | 2 +-
 src/tools/rls            | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/doc/book b/src/doc/book
index d09c9e8144ed3..08e79609ce885 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit d09c9e8144ed32170b7596abb145ade8b097acaf
+Subproject commit 08e79609ce88583fa7286157dfe497486a09fabe
diff --git a/src/doc/nomicon b/src/doc/nomicon
index a4322ccb289a4..0ee3f7265e9d0 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit a4322ccb289a43cc238d4536982f184a3eec9ba7
+Subproject commit 0ee3f7265e9d09746d901cef6f1f300baff1d923
diff --git a/src/doc/reference b/src/doc/reference
index 1abfbaa70313f..36adc6ae504c6 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 1abfbaa70313fdf527cf799ffd9b9a096a62105c
+Subproject commit 36adc6ae504c6e0343ab5d7b3871f0a2a71236da
diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins
index 6b9281d2b2f0e..0b9844764ea1f 160000
--- a/src/libcompiler_builtins
+++ b/src/libcompiler_builtins
@@ -1 +1 @@
-Subproject commit 6b9281d2b2f0ebb94838814b1e8ace2de4b7035b
+Subproject commit 0b9844764ea1f99ea11a7917a4f3ba7fd2db775c
diff --git a/src/liblibc b/src/liblibc
index 2a5b50b7f7f53..44e4018e1a377 160000
--- a/src/liblibc
+++ b/src/liblibc
@@ -1 +1 @@
-Subproject commit 2a5b50b7f7f539a0fd201331d6c1e0534aa332f5
+Subproject commit 44e4018e1a37716286ec98cb5b7dd7d33ecaf940
diff --git a/src/tools/rls b/src/tools/rls
index 5d4bbd9052fe2..bfe80cfa8db75 160000
--- a/src/tools/rls
+++ b/src/tools/rls
@@ -1 +1 @@
-Subproject commit 5d4bbd9052fe2af849a7d017b85df98ad002c20f
+Subproject commit bfe80cfa8db75500e67ca8762465d27662674637

From b79b450965d9452e7fab713f429ae6391860ad9d Mon Sep 17 00:00:00 2001
From: Inokentiy Babushkin <twk@twki.de>
Date: Wed, 11 Oct 2017 22:00:24 +0200
Subject: [PATCH 13/13] (kind of) fixed build.

---
 src/librustc_metadata/decoder.rs                       |  2 +-
 src/libsyntax_pos/hygiene.rs                           | 10 +++-------
 src/llvm                                               |  2 +-
 .../compile-fail-fulldeps/auxiliary/macro_spans_lib.rs |  5 +++--
 src/test/compile-fail-fulldeps/macro-spans.rs          |  2 +-
 src/tools/cargo                                        |  2 +-
 src/tools/rls                                          |  2 +-
 src/tools/rust-installer                               |  2 +-
 8 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 2b8599a7988e5..a8176bf7a1654 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -274,7 +274,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
         let sess = if let Some(sess) = self.sess {
             sess
         } else {
-            return Ok(Span { lo, hi, ctxt });
+            return Ok(Span::new(lo, hi, ctxt));
         };
 
         let (lo, hi) = if lo > hi {
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index eabde196f73a0..b8a4eaaef4977 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -189,10 +189,10 @@ impl HygieneData {
 
                 mark_queue.push_back(data.parent);
                 if let Some(ref info) = data.expn_info {
-                    ctxt_queue.push_back(info.call_site.ctxt);
+                    ctxt_queue.push_back(info.call_site.ctxt());
 
                     if let Some(span) = info.callee.span {
-                        ctxt_queue.push_back(span.ctxt);
+                        ctxt_queue.push_back(span.ctxt());
                     }
                 }
 
@@ -272,11 +272,7 @@ impl ImportedHygieneData {
     }
 
     pub fn translate_span(&self, external: Span) -> Span {
-        Span {
-            lo: external.lo,
-            hi: external.hi,
-            ctxt: self.translate_ctxt(external.ctxt),
-        }
+        Span::new(external.lo(), external.hi(), self.translate_ctxt(external.ctxt()))
     }
 
     fn translate_mark_data(&self, data: MarkData) -> MarkData {
diff --git a/src/llvm b/src/llvm
index d9e7d2696e419..c7a16bd57c2a9 160000
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit d9e7d2696e41983b6b5a0b4fac604b4e548a84d3
+Subproject commit c7a16bd57c2a9c643a52f0cebecdaf0b6a996da1
diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs
index 739e37feeae29..eeba255923407 100644
--- a/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs
+++ b/src/test/compile-fail-fulldeps/auxiliary/macro_spans_lib.rs
@@ -8,18 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[macro_export]
 macro_rules! abc {
     ($name:ident) => {
         mod $name {
             macro_rules! $name {
                 ($name2:ident) => {
                     struct $name {
-                        $name2: u8,
+                        $name2: $name,
                     }
                 }
             }
 
-            $name!(AStruct)
+            $name!(some_field);
         }
     }
 }
diff --git a/src/test/compile-fail-fulldeps/macro-spans.rs b/src/test/compile-fail-fulldeps/macro-spans.rs
index a3f7a92af719e..3a9994c7505af 100644
--- a/src/test/compile-fail-fulldeps/macro-spans.rs
+++ b/src/test/compile-fail-fulldeps/macro-spans.rs
@@ -13,6 +13,6 @@
 #[macro_use]
 extern crate macro_spans_lib;
 
-abc!(Name)
+abc!(Name); //~ ERROR recursive type `Name::Name` has infinite size
 
 fn main() { }
diff --git a/src/tools/cargo b/src/tools/cargo
index 7704f7b1fd526..e447ac7e94b7f 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 7704f7b1fd52607104cc7fdc435d636c9de1fe90
+Subproject commit e447ac7e94b7f56ab13e361f9e324dafe3eb0a34
diff --git a/src/tools/rls b/src/tools/rls
index bfe80cfa8db75..93b47d14cef57 160000
--- a/src/tools/rls
+++ b/src/tools/rls
@@ -1 +1 @@
-Subproject commit bfe80cfa8db75500e67ca8762465d27662674637
+Subproject commit 93b47d14cef5720bba7cfb4dcb8078fbf1f706c1
diff --git a/src/tools/rust-installer b/src/tools/rust-installer
index b4ff403041f17..0ddd53c4bc2a7 160000
--- a/src/tools/rust-installer
+++ b/src/tools/rust-installer
@@ -1 +1 @@
-Subproject commit b4ff403041f17957f735ad750c3241a3a428b9b7
+Subproject commit 0ddd53c4bc2a76df565a1c1fc0cc6f19f254b51e