From 4a384089402cb4b90674554467b7a506a00a5d59 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sat, 8 Dec 2018 20:30:38 +0300
Subject: [PATCH 1/6] Remove `eliminate_crate_var` and special pretty-printing
 for `$crate`

---
 src/librustc/hir/print.rs            |  9 ++---
 src/librustc_resolve/lib.rs          |  4 --
 src/librustc_resolve/macros.rs       | 57 +---------------------------
 src/libsyntax/ext/base.rs            |  2 -
 src/libsyntax/ext/expand.rs          |  5 +--
 src/libsyntax/print/pprust.rs        | 25 +-----------
 src/libsyntax_ext/deriving/custom.rs |  1 -
 src/libsyntax_pos/hygiene.rs         | 16 --------
 8 files changed, 7 insertions(+), 112 deletions(-)

diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index a24f2fa4bc652..5c6845181afd1 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1622,8 +1622,7 @@ impl<'a> State<'a> {
             if i > 0 {
                 self.s.word("::")?
             }
-            if segment.ident.name != keywords::PathRoot.name() &&
-               segment.ident.name != keywords::DollarCrate.name() {
+            if segment.ident.name != keywords::PathRoot.name() {
                self.print_ident(segment.ident)?;
                segment.with_generic_args(|generic_args| {
                    self.print_generic_args(generic_args, segment.infer_types,
@@ -1636,8 +1635,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_path_segment(&mut self, segment: &hir::PathSegment) -> io::Result<()> {
-        if segment.ident.name != keywords::PathRoot.name() &&
-           segment.ident.name != keywords::DollarCrate.name() {
+        if segment.ident.name != keywords::PathRoot.name() {
            self.print_ident(segment.ident)?;
            segment.with_generic_args(|generic_args| {
                self.print_generic_args(generic_args, segment.infer_types, false)
@@ -1664,8 +1662,7 @@ impl<'a> State<'a> {
                     if i > 0 {
                         self.s.word("::")?
                     }
-                    if segment.ident.name != keywords::PathRoot.name() &&
-                       segment.ident.name != keywords::DollarCrate.name() {
+                    if segment.ident.name != keywords::PathRoot.name() {
                         self.print_ident(segment.ident)?;
                         segment.with_generic_args(|generic_args| {
                             self.print_generic_args(generic_args,
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 36f4497b77fe5..794e5741d62ca 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1173,10 +1173,6 @@ impl<'a> ModuleData<'a> {
         }
     }
 
-    fn is_local(&self) -> bool {
-        self.normal_ancestor_id.is_local()
-    }
-
     fn nearest_item_scope(&'a self) -> Module<'a> {
         if self.is_trait() { self.parent.unwrap() } else { self }
     }
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 32f0d84342edd..81633c8f57f9e 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -10,7 +10,7 @@
 
 use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
 use {CrateLint, Resolver, ResolutionError, ScopeSet, Weak};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
+use {Module, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
 use {is_known_tool, resolve_error};
 use ModuleOrUniformRoot;
 use Namespace::*;
@@ -30,8 +30,6 @@ use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
 use syntax::ext::hygiene::{self, Mark};
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{feature_err, is_builtin_attr_name, GateIssue};
-use syntax::fold::{self, Folder};
-use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{Span, DUMMY_SP};
@@ -138,58 +136,6 @@ impl<'a> base::Resolver for Resolver<'a> {
         mark
     }
 
-    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
-        struct EliminateCrateVar<'b, 'a: 'b>(
-            &'b mut Resolver<'a>, Span
-        );
-
-        impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
-            fn fold_path(&mut self, path: ast::Path) -> ast::Path {
-                match self.fold_qpath(None, path) {
-                    (None, path) => path,
-                    _ => unreachable!(),
-                }
-            }
-
-            fn fold_qpath(&mut self, mut qself: Option<ast::QSelf>, mut path: ast::Path)
-                          -> (Option<ast::QSelf>, ast::Path) {
-                qself = qself.map(|ast::QSelf { ty, path_span, position }| {
-                    ast::QSelf {
-                        ty: self.fold_ty(ty),
-                        path_span: self.new_span(path_span),
-                        position,
-                    }
-                });
-
-                if path.segments[0].ident.name == keywords::DollarCrate.name() {
-                    let module = self.0.resolve_crate_root(path.segments[0].ident);
-                    path.segments[0].ident.name = keywords::PathRoot.name();
-                    if !module.is_local() {
-                        let span = path.segments[0].ident.span;
-                        path.segments.insert(1, match module.kind {
-                            ModuleKind::Def(_, name) => ast::PathSegment::from_ident(
-                                ast::Ident::with_empty_ctxt(name).with_span_pos(span)
-                            ),
-                            _ => unreachable!(),
-                        });
-                        if let Some(qself) = &mut qself {
-                            qself.position += 1;
-                        }
-                    }
-                }
-                (qself, path)
-            }
-
-            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-                fold::noop_fold_mac(mac, self)
-            }
-        }
-
-        let ret = EliminateCrateVar(self, item.span).fold_item(item);
-        assert!(ret.len() == 1);
-        ret.into_iter().next().unwrap()
-    }
-
     fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
                                             derives: &[Mark]) {
         let invocation = self.invocations[&mark];
@@ -259,7 +205,6 @@ impl<'a> base::Resolver for Resolver<'a> {
             self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
                                                             normal_module_def_id);
             invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
-            invoc.expansion_data.mark.set_is_builtin(def_id.krate == CrateNum::BuiltinMacros);
         }
 
         Ok(Some(ext))
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 310cf27689bc5..b807a65f6aed6 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -732,7 +732,6 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension);
 pub trait Resolver {
     fn next_node_id(&mut self) -> ast::NodeId;
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
-    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>;
 
     fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
                                             derives: &[Mark]);
@@ -766,7 +765,6 @@ pub struct DummyResolver;
 impl Resolver for DummyResolver {
     fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
     fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
-    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }
 
     fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
                                             _derives: &[Mark]) {}
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 03c7aa9682477..57ccc3e981720 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -203,10 +203,7 @@ fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
         if i != 0 {
             path_str.push_str("::");
         }
-
-        if segment.ident.name != keywords::PathRoot.name() &&
-            segment.ident.name != keywords::DollarCrate.name()
-        {
+        if segment.ident.name != keywords::PathRoot.name() {
             path_str.push_str(&segment.ident.as_str())
         }
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 41165c7e36d58..8250587f9e085 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -16,7 +16,6 @@ use util::parser::{self, AssocOp, Fixity};
 use attr;
 use source_map::{self, SourceMap, Spanned};
 use syntax_pos::{self, BytePos};
-use syntax_pos::hygiene::{Mark, SyntaxContext};
 use parse::token::{self, BinOpToken, Token};
 use parse::lexer::comments;
 use parse::{self, ParseSess};
@@ -724,12 +723,8 @@ pub trait PrintState<'a> {
             if i > 0 {
                 self.writer().word("::")?
             }
-            if segment.ident.name != keywords::PathRoot.name() &&
-               segment.ident.name != keywords::DollarCrate.name()
-            {
+            if segment.ident.name != keywords::PathRoot.name() {
                 self.writer().word(segment.ident.as_str().get())?;
-            } else if segment.ident.name == keywords::DollarCrate.name() {
-                self.print_dollar_crate(segment.ident.span.ctxt())?;
             }
         }
         Ok(())
@@ -842,19 +837,6 @@ pub trait PrintState<'a> {
     }
 
     fn nbsp(&mut self) -> io::Result<()> { self.writer().word(" ") }
-
-    fn print_dollar_crate(&mut self, mut ctxt: SyntaxContext) -> io::Result<()> {
-        if let Some(mark) = ctxt.adjust(Mark::root()) {
-            // Make a best effort to print something that complies
-            if mark.is_builtin() {
-                if let Some(name) = std_inject::injected_crate_name() {
-                    self.writer().word("::")?;
-                    self.writer().word(name)?;
-                }
-            }
-        }
-        Ok(())
-    }
 }
 
 impl<'a> PrintState<'a> for State<'a> {
@@ -2463,14 +2445,11 @@ impl<'a> State<'a> {
                           colons_before_params: bool)
                           -> io::Result<()>
     {
-        if segment.ident.name != keywords::PathRoot.name() &&
-           segment.ident.name != keywords::DollarCrate.name() {
+        if segment.ident.name != keywords::PathRoot.name() {
             self.print_ident(segment.ident)?;
             if let Some(ref args) = segment.args {
                 self.print_generic_args(args, colons_before_params)?;
             }
-        } else if segment.ident.name == keywords::DollarCrate.name() {
-            self.print_dollar_crate(segment.ident.span.ctxt())?;
         }
         Ok(())
     }
diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs
index 5c82d1911383e..cc2fa68568713 100644
--- a/src/libsyntax_ext/deriving/custom.rs
+++ b/src/libsyntax_ext/deriving/custom.rs
@@ -74,7 +74,6 @@ impl MultiItemModifier for ProcMacroDerive {
         // Mark attributes as known, and used.
         MarkAttrs(&self.attrs).visit_item(&item);
 
-        let item = ecx.resolver.eliminate_crate_var(item);
         let token = Token::interpolated(token::NtItem(item));
         let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into();
 
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 74f63b5e2c604..72b48ede58e17 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -47,7 +47,6 @@ pub struct Mark(u32);
 struct MarkData {
     parent: Mark,
     default_transparency: Transparency,
-    is_builtin: bool,
     expn_info: Option<ExpnInfo>,
 }
 
@@ -77,7 +76,6 @@ impl Mark {
                 parent,
                 // By default expansions behave like `macro_rules`.
                 default_transparency: Transparency::SemiTransparent,
-                is_builtin: false,
                 expn_info: None,
             });
             Mark(data.marks.len() as u32 - 1)
@@ -121,18 +119,6 @@ impl Mark {
         HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
     }
 
-    #[inline]
-    pub fn is_builtin(self) -> bool {
-        assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].is_builtin)
-    }
-
-    #[inline]
-    pub fn set_is_builtin(self, is_builtin: bool) {
-        assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin)
-    }
-
     pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
         HygieneData::with(|data| {
             while self != ancestor {
@@ -206,7 +192,6 @@ impl HygieneData {
                 // If the root is opaque, then loops searching for an opaque mark
                 // will automatically stop after reaching it.
                 default_transparency: Transparency::Opaque,
-                is_builtin: true,
                 expn_info: None,
             }],
             syntax_contexts: vec![SyntaxContextData {
@@ -262,7 +247,6 @@ impl SyntaxContext {
             data.marks.push(MarkData {
                 parent: Mark::root(),
                 default_transparency: Transparency::SemiTransparent,
-                is_builtin: false,
                 expn_info: Some(expansion_info),
             });
 

From 8a8ef260bef994c1e9d3444356fa9f33c01943c1 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sat, 8 Dec 2018 21:00:39 +0300
Subject: [PATCH 2/6] proc_macro: Validate tokens coming from the compiler
 again

---
 src/libproc_macro/lib.rs               |  21 -----
 src/libsyntax_ext/proc_macro_server.rs | 107 +++++++++++++------------
 2 files changed, 56 insertions(+), 72 deletions(-)

diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index f2b85832dac31..ebba5c81fe077 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -729,11 +729,6 @@ impl Punct {
     /// which can be further configured with the `set_span` method below.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn new(ch: char, spacing: Spacing) -> Punct {
-        const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
-                                       '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
-        if !LEGAL_CHARS.contains(&ch) {
-            panic!("unsupported character `{:?}`", ch)
-        }
         Punct(bridge::client::Punct::new(ch, spacing))
     }
 
@@ -800,16 +795,6 @@ impl fmt::Debug for Punct {
 pub struct Ident(bridge::client::Ident);
 
 impl Ident {
-    fn is_valid(string: &str) -> bool {
-        let mut chars = string.chars();
-        if let Some(start) = chars.next() {
-            (start == '_' || start.is_xid_start())
-                && chars.all(|cont| cont == '_' || cont.is_xid_continue())
-        } else {
-            false
-        }
-    }
-
     /// Creates a new `Ident` with the given `string` as well as the specified
     /// `span`.
     /// The `string` argument must be a valid identifier permitted by the
@@ -831,18 +816,12 @@ impl Ident {
     /// tokens, requires a `Span` to be specified at construction.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn new(string: &str, span: Span) -> Ident {
-        if !Ident::is_valid(string) {
-            panic!("`{:?}` is not a valid identifier", string)
-        }
         Ident(bridge::client::Ident::new(string, span.0, false))
     }
 
     /// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
     #[unstable(feature = "proc_macro_raw_ident", issue = "54723")]
     pub fn new_raw(string: &str, span: Span) -> Ident {
-        if !Ident::is_valid(string) {
-            panic!("`{:?}` is not a valid identifier", string)
-        }
         Ident(bridge::client::Ident::new(string, span.0, true))
     }
 
diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs
index a04d6c92b7817..ea4a8afc0aabd 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax_ext/proc_macro_server.rs
@@ -81,29 +81,23 @@ impl FromInternal<(TokenStream, &'_ ParseSess, &'_ mut Vec<Self>)>
                     $($field $(: $value)*,)*
                     span,
                 })
-            )
+            );
+            ($ty:ident::$method:ident($($value:expr),*)) => (
+                TokenTree::$ty(self::$ty::$method($($value,)* span))
+            );
         }
         macro_rules! op {
             ($a:expr) => {
-                tt!(Punct { ch: $a, joint })
+                tt!(Punct::new($a, joint))
             };
             ($a:expr, $b:expr) => {{
-                stack.push(tt!(Punct { ch: $b, joint }));
-                tt!(Punct {
-                    ch: $a,
-                    joint: true
-                })
+                stack.push(tt!(Punct::new($b, joint)));
+                tt!(Punct::new($a, true))
             }};
             ($a:expr, $b:expr, $c:expr) => {{
-                stack.push(tt!(Punct { ch: $c, joint }));
-                stack.push(tt!(Punct {
-                    ch: $b,
-                    joint: true
-                }));
-                tt!(Punct {
-                    ch: $a,
-                    joint: true
-                })
+                stack.push(tt!(Punct::new($c, joint)));
+                stack.push(tt!(Punct::new($b, true)));
+                tt!(Punct::new($a, true))
             }};
         }
 
@@ -156,20 +150,11 @@ impl FromInternal<(TokenStream, &'_ ParseSess, &'_ mut Vec<Self>)>
             Question => op!('?'),
             SingleQuote => op!('\''),
 
-            Ident(ident, is_raw) => tt!(Ident {
-                sym: ident.name,
-                is_raw
-            }),
+            Ident(ident, is_raw) => tt!(Ident::new(ident.name, is_raw)),
             Lifetime(ident) => {
                 let ident = ident.without_first_quote();
-                stack.push(tt!(Ident {
-                    sym: ident.name,
-                    is_raw: false
-                }));
-                tt!(Punct {
-                    ch: '\'',
-                    joint: true
-                })
+                stack.push(tt!(Ident::new(ident.name, false)));
+                tt!(Punct::new('\'', true))
             }
             Literal(lit, suffix) => tt!(Literal { lit, suffix }),
             DocComment(c) => {
@@ -193,15 +178,9 @@ impl FromInternal<(TokenStream, &'_ ParseSess, &'_ mut Vec<Self>)>
                     span: DelimSpan::from_single(span),
                 }));
                 if style == ast::AttrStyle::Inner {
-                    stack.push(tt!(Punct {
-                        ch: '!',
-                        joint: false
-                    }));
+                    stack.push(tt!(Punct::new('!', false)));
                 }
-                tt!(Punct {
-                    ch: '#',
-                    joint: false
-                })
+                tt!(Punct::new('#', false))
             }
 
             Interpolated(_) => {
@@ -237,7 +216,7 @@ impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
                 )
                 .into();
             }
-            TokenTree::Ident(self::Ident { sym, span, is_raw }) => {
+            TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
                 let token = Ident(ast::Ident::new(sym, span), is_raw);
                 return tokenstream::TokenTree::Token(span, token).into();
             }
@@ -338,11 +317,48 @@ pub struct Punct {
     span: Span,
 }
 
+impl Punct {
+    fn new(ch: char, joint: bool, span: Span) -> Punct {
+        const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
+                                       '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
+        if !LEGAL_CHARS.contains(&ch) {
+            panic!("unsupported character `{:?}`", ch)
+        }
+        Punct { ch, joint, span }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Ident {
     sym: Symbol,
-    span: Span,
     is_raw: bool,
+    span: Span,
+}
+
+impl Ident {
+    fn is_valid(string: &str) -> bool {
+        let mut chars = string.chars();
+        if let Some(start) = chars.next() {
+            (start == '_' || start.is_xid_start())
+                && chars.all(|cont| cont == '_' || cont.is_xid_continue())
+        } else {
+            false
+        }
+    }
+    fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident {
+        let string = sym.as_str().get();
+        if !Self::is_valid(string) {
+            panic!("`{:?}` is not a valid identifier", string)
+        }
+        if is_raw {
+            let normalized_sym = Symbol::intern(string);
+            if normalized_sym == keywords::Underscore.name() ||
+               ast::Ident::with_empty_ctxt(normalized_sym).is_path_segment_keyword() {
+                panic!("`{:?}` is not a valid raw identifier", string)
+            }
+        }
+        Ident { sym, is_raw, span }
+    }
 }
 
 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
@@ -492,11 +508,7 @@ impl server::Group for Rustc<'_> {
 
 impl server::Punct for Rustc<'_> {
     fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
-        Punct {
-            ch,
-            joint: spacing == Spacing::Joint,
-            span: server::Span::call_site(self),
-        }
+        Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
     }
     fn as_char(&mut self, punct: Self::Punct) -> char {
         punct.ch
@@ -518,14 +530,7 @@ impl server::Punct for Rustc<'_> {
 
 impl server::Ident for Rustc<'_> {
     fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
-        let sym = Symbol::intern(string);
-        if is_raw
-            && (sym == keywords::Underscore.name()
-                || ast::Ident::with_empty_ctxt(sym).is_path_segment_keyword())
-        {
-            panic!("`{:?}` is not a valid raw identifier", string)
-        }
-        Ident { sym, span, is_raw }
+        Ident::new(Symbol::intern(string), is_raw, span)
     }
     fn span(&mut self, ident: Self::Ident) -> Self::Span {
         ident.span

From 2bc67da378db40b23a426ea6384b2660c29a002c Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 9 Dec 2018 17:31:12 +0300
Subject: [PATCH 3/6] proc_macro: Accept `$crate` as an identifier if it comes
 from the compiler

---
 src/libsyntax_ext/proc_macro_server.rs           |  6 ++++++
 src/test/ui/proc-macro/auxiliary/dollar-crate.rs | 12 ++++++++++++
 src/test/ui/proc-macro/dollar-crate.rs           | 16 ++++++++++++++++
 3 files changed, 34 insertions(+)
 create mode 100644 src/test/ui/proc-macro/auxiliary/dollar-crate.rs
 create mode 100644 src/test/ui/proc-macro/dollar-crate.rs

diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs
index ea4a8afc0aabd..ca960cbe41b5d 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax_ext/proc_macro_server.rs
@@ -150,6 +150,8 @@ impl FromInternal<(TokenStream, &'_ ParseSess, &'_ mut Vec<Self>)>
             Question => op!('?'),
             SingleQuote => op!('\''),
 
+            Ident(ident, false) if ident.name == keywords::DollarCrate.name() =>
+                tt!(Ident::dollar_crate()),
             Ident(ident, is_raw) => tt!(Ident::new(ident.name, is_raw)),
             Lifetime(ident) => {
                 let ident = ident.without_first_quote();
@@ -359,6 +361,10 @@ impl Ident {
         }
         Ident { sym, is_raw, span }
     }
+    fn dollar_crate(span: Span) -> Ident {
+        // `$crate` is accepted as an ident only if it comes from the compiler.
+        Ident { sym: keywords::DollarCrate.name(), is_raw: false, span }
+    }
 }
 
 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs
new file mode 100644
index 0000000000000..b0727a33332e7
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn normalize(input: TokenStream) -> TokenStream {
+    input.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs
new file mode 100644
index 0000000000000..b8b1ddd5d1cbb
--- /dev/null
+++ b/src/test/ui/proc-macro/dollar-crate.rs
@@ -0,0 +1,16 @@
+// compile-pass
+// aux-build:dollar-crate.rs
+
+extern crate dollar_crate;
+
+type S = u8;
+
+macro_rules! check { () => {
+    dollar_crate::normalize! {
+        type A = $crate::S;
+    }
+}}
+
+check!();
+
+fn main() {}

From 69c66286a9a3240309cc5474478ad0a2186e2bce Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 9 Dec 2018 17:46:12 +0300
Subject: [PATCH 4/6] Reintroduce special pretty-printing for `$crate` when
 it's necessary for proc macros

---
 src/librustc_resolve/build_reduced_graph.rs   |  11 +
 src/libsyntax/print/pprust.rs                 |  27 +-
 src/libsyntax_pos/hygiene.rs                  |  26 +-
 src/test/pretty/issue-4264.pp                 |   4 +-
 .../auxiliary/dollar-crate-external.rs        |  16 ++
 .../ui/proc-macro/auxiliary/dollar-crate.rs   |  18 +-
 src/test/ui/proc-macro/dollar-crate.rs        |  32 ++-
 src/test/ui/proc-macro/dollar-crate.stderr    |  23 ++
 src/test/ui/proc-macro/dollar-crate.stdout    | 260 ++++++++++++++++++
 9 files changed, 403 insertions(+), 14 deletions(-)
 create mode 100644 src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
 create mode 100644 src/test/ui/proc-macro/dollar-crate.stderr
 create mode 100644 src/test/ui/proc-macro/dollar-crate.stdout

diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index f082d776969eb..6cfa9f95082e0 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -1035,4 +1035,15 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
         }
         visit::walk_attribute(self, attr);
     }
+
+    fn visit_ident(&mut self, ident: Ident) {
+        if ident.name == keywords::DollarCrate.name() {
+            let name = match self.resolver.resolve_crate_root(ident).kind {
+                ModuleKind::Def(_, name) if name != keywords::Invalid.name() => name,
+                _ => keywords::Crate.name(),
+            };
+            ident.span.ctxt().set_dollar_crate_name(name);
+        }
+        visit::walk_ident(self, ident);
+    }
 }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 8250587f9e085..5e7707f4e5c3c 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -724,7 +724,11 @@ pub trait PrintState<'a> {
                 self.writer().word("::")?
             }
             if segment.ident.name != keywords::PathRoot.name() {
-                self.writer().word(segment.ident.as_str().get())?;
+                if segment.ident.name == keywords::DollarCrate.name() {
+                    self.print_dollar_crate(segment.ident)?;
+                } else {
+                    self.writer().word(segment.ident.as_str().get())?;
+                }
             }
         }
         Ok(())
@@ -837,6 +841,21 @@ pub trait PrintState<'a> {
     }
 
     fn nbsp(&mut self) -> io::Result<()> { self.writer().word(" ") }
+
+    // AST pretty-printer is used as a fallback for turning AST structures into token streams for
+    // proc macros. Additionally, proc macros may stringify their input and expect it survive the
+    // stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
+    // So we need to somehow pretty-print `$crate` in paths in a way preserving at least some of
+    // its hygiene data, most importantly name of the crate it refers to.
+    // As a result we print `$crate` as `crate` if it refers to the local crate
+    // and as `::other_crate_name` if it refers to some other crate.
+    fn print_dollar_crate(&mut self, ident: ast::Ident) -> io::Result<()> {
+        let name = ident.span.ctxt().dollar_crate_name();
+        if !ast::Ident::with_empty_ctxt(name).is_path_segment_keyword() {
+            self.writer().word("::")?;
+        }
+        self.writer().word(name.as_str().get())
+    }
 }
 
 impl<'a> PrintState<'a> for State<'a> {
@@ -2446,7 +2465,11 @@ impl<'a> State<'a> {
                           -> io::Result<()>
     {
         if segment.ident.name != keywords::PathRoot.name() {
-            self.print_ident(segment.ident)?;
+            if segment.ident.name == keywords::DollarCrate.name() {
+                self.print_dollar_crate(segment.ident)?;
+            } else {
+                self.print_ident(segment.ident)?;
+            }
             if let Some(ref args) = segment.args {
                 self.print_generic_args(args, colons_before_params)?;
             }
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 72b48ede58e17..3dc884a94c0dc 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -18,11 +18,11 @@
 use GLOBALS;
 use Span;
 use edition::{Edition, DEFAULT_EDITION};
-use symbol::Symbol;
+use symbol::{keywords, Symbol};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use std::fmt;
+use std::{fmt, mem};
 
 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
 #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
@@ -37,6 +37,8 @@ struct SyntaxContextData {
     opaque: SyntaxContext,
     // This context, but with all transparent marks filtered away.
     opaque_and_semitransparent: SyntaxContext,
+    // Name of the crate to which `$crate` with this context would resolve.
+    dollar_crate_name: Symbol,
 }
 
 /// A mark is a unique id associated with a macro expansion.
@@ -200,6 +202,7 @@ impl HygieneData {
                 prev_ctxt: SyntaxContext(0),
                 opaque: SyntaxContext(0),
                 opaque_and_semitransparent: SyntaxContext(0),
+                dollar_crate_name: keywords::DollarCrate.name(),
             }],
             markings: FxHashMap::default(),
             default_edition: DEFAULT_EDITION,
@@ -258,6 +261,7 @@ impl SyntaxContext {
                 prev_ctxt: SyntaxContext::empty(),
                 opaque: SyntaxContext::empty(),
                 opaque_and_semitransparent: SyntaxContext::empty(),
+                dollar_crate_name: keywords::DollarCrate.name(),
             });
             SyntaxContext(data.syntax_contexts.len() as u32 - 1)
         })
@@ -324,6 +328,7 @@ impl SyntaxContext {
                         prev_ctxt,
                         opaque: new_opaque,
                         opaque_and_semitransparent: new_opaque,
+                        dollar_crate_name: keywords::DollarCrate.name(),
                     });
                     new_opaque
                 });
@@ -341,6 +346,7 @@ impl SyntaxContext {
                         prev_ctxt,
                         opaque,
                         opaque_and_semitransparent: new_opaque_and_semitransparent,
+                        dollar_crate_name: keywords::DollarCrate.name(),
                     });
                     new_opaque_and_semitransparent
                 });
@@ -356,6 +362,7 @@ impl SyntaxContext {
                     prev_ctxt,
                     opaque,
                     opaque_and_semitransparent,
+                    dollar_crate_name: keywords::DollarCrate.name(),
                 });
                 new_opaque_and_semitransparent_and_transparent
             })
@@ -510,6 +517,21 @@ impl SyntaxContext {
     pub fn outer(self) -> Mark {
         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
     }
+
+    pub fn dollar_crate_name(self) -> Symbol {
+        HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name)
+    }
+
+    pub fn set_dollar_crate_name(self, dollar_crate_name: Symbol) {
+        HygieneData::with(|data| {
+            let prev_dollar_crate_name = mem::replace(
+                &mut data.syntax_contexts[self.0 as usize].dollar_crate_name, dollar_crate_name
+            );
+            assert!(dollar_crate_name == prev_dollar_crate_name ||
+                    prev_dollar_crate_name == keywords::DollarCrate.name(),
+                    "$crate name is reset for a syntax context");
+        })
+    }
 }
 
 impl fmt::Debug for SyntaxContext {
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 5f42b86c82a81..3b01ab3a47b6a 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -39,8 +39,8 @@
 
 
 
-                  ((::fmt::format as
-                       for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::fmt::Arguments>::new_v1
+                  (($crate::fmt::format as
+                       for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<$crate::fmt::Arguments>::new_v1
                                                                                                            as
                                                                                                            fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test"
                                                                                                                                                                                                                           as
diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
new file mode 100644
index 0000000000000..8f15a2b975bf3
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
@@ -0,0 +1,16 @@
+pub type S = u8;
+
+#[macro_export]
+macro_rules! external {
+    () => {
+        dollar_crate::m! {
+            struct M($crate::S);
+        }
+
+        #[dollar_crate::a]
+        struct A($crate::S);
+
+        #[derive(dollar_crate::d)]
+        struct D($crate::S);
+    };
+}
diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs
index b0727a33332e7..d0ea850d4e323 100644
--- a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs
+++ b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs
@@ -7,6 +7,22 @@ extern crate proc_macro;
 use proc_macro::TokenStream;
 
 #[proc_macro]
-pub fn normalize(input: TokenStream) -> TokenStream {
+pub fn m(input: TokenStream) -> TokenStream {
+    println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input);
+    println!("PROC MACRO INPUT: {:#?}", input);
+    input.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn a(_args: TokenStream, input: TokenStream) -> TokenStream {
+    println!("ATTRIBUTE INPUT (PRETTY-PRINTED): {}", input);
+    println!("ATTRIBUTE INPUT: {:#?}", input);
+    input.into_iter().collect()
+}
+
+#[proc_macro_derive(d)]
+pub fn d(input: TokenStream) -> TokenStream {
+    println!("DERIVE INPUT (PRETTY-PRINTED): {}", input);
+    println!("DERIVE INPUT: {:#?}", input);
     input.into_iter().collect()
 }
diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs
index b8b1ddd5d1cbb..3f4a01cb2dca9 100644
--- a/src/test/ui/proc-macro/dollar-crate.rs
+++ b/src/test/ui/proc-macro/dollar-crate.rs
@@ -1,16 +1,34 @@
-// compile-pass
+// edition:2018
+// compile-flags:--extern dollar_crate --extern dollar_crate_external
 // aux-build:dollar-crate.rs
+// aux-build:dollar-crate-external.rs
 
-extern crate dollar_crate;
+// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
+// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
+// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
 
 type S = u8;
 
-macro_rules! check { () => {
-    dollar_crate::normalize! {
-        type A = $crate::S;
+mod local {
+    macro_rules! local {
+        () => {
+            dollar_crate::m! {
+                struct M($crate::S);
+            }
+
+            #[dollar_crate::a]
+            struct A($crate::S);
+
+            #[derive(dollar_crate::d)]
+            struct D($crate::S); //~ ERROR the name `D` is defined multiple times
+        };
     }
-}}
 
-check!();
+    local!();
+}
+
+mod external {
+    dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
+}
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr
new file mode 100644
index 0000000000000..171562a5aff20
--- /dev/null
+++ b/src/test/ui/proc-macro/dollar-crate.stderr
@@ -0,0 +1,23 @@
+error[E0428]: the name `D` is defined multiple times
+  --> $DIR/dollar-crate.rs:23:13
+   |
+LL |             struct D($crate::S); //~ ERROR the name `D` is defined multiple times
+   |             ^^^^^^^^^^^^^^^^^^^^ `D` redefined here
+...
+LL |     local!();
+   |     --------- in this macro invocation
+   |
+   = note: `D` must be defined only once in the type namespace of this module
+
+error[E0428]: the name `D` is defined multiple times
+  --> $DIR/dollar-crate.rs:31:5
+   |
+LL |     dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `D` redefined here
+   |
+   = note: `D` must be defined only once in the type namespace of this module
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout
new file mode 100644
index 0000000000000..8e254854e32e6
--- /dev/null
+++ b/src/test/ui/proc-macro/dollar-crate.stdout
@@ -0,0 +1,260 @@
+PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ;
+PROC MACRO INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #2 bytes(LO..HI)
+    },
+    Ident {
+        ident: "M",
+        span: #2 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #2 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #2 bytes(LO..HI)
+            }
+        ],
+        span: #2 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #2 bytes(LO..HI)
+    }
+]
+ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S);
+ATTRIBUTE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #0 bytes(0..0)
+    },
+    Ident {
+        ident: "A",
+        span: #0 bytes(0..0)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "crate",
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #0 bytes(0..0)
+            },
+            Ident {
+                ident: "S",
+                span: #0 bytes(0..0)
+            }
+        ],
+        span: #0 bytes(0..0)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #0 bytes(0..0)
+    }
+]
+DERIVE INPUT (PRETTY-PRINTED): struct D(crate::S);
+DERIVE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #0 bytes(0..0)
+    },
+    Ident {
+        ident: "D",
+        span: #0 bytes(0..0)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "crate",
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #0 bytes(0..0)
+            },
+            Ident {
+                ident: "S",
+                span: #0 bytes(0..0)
+            }
+        ],
+        span: #0 bytes(0..0)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #0 bytes(0..0)
+    }
+]
+PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ;
+PROC MACRO INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #10 bytes(LO..HI)
+    },
+    Ident {
+        ident: "M",
+        span: #10 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #10 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #10 bytes(LO..HI)
+            }
+        ],
+        span: #10 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #10 bytes(LO..HI)
+    }
+]
+ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(::dollar_crate_external::S);
+ATTRIBUTE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #0 bytes(0..0)
+    },
+    Ident {
+        ident: "A",
+        span: #0 bytes(0..0)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #0 bytes(0..0)
+            },
+            Ident {
+                ident: "dollar_crate_external",
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #0 bytes(0..0)
+            },
+            Ident {
+                ident: "S",
+                span: #0 bytes(0..0)
+            }
+        ],
+        span: #0 bytes(0..0)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #0 bytes(0..0)
+    }
+]
+DERIVE INPUT (PRETTY-PRINTED): struct D(::dollar_crate_external::S);
+DERIVE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #0 bytes(0..0)
+    },
+    Ident {
+        ident: "D",
+        span: #0 bytes(0..0)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #0 bytes(0..0)
+            },
+            Ident {
+                ident: "dollar_crate_external",
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #0 bytes(0..0)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #0 bytes(0..0)
+            },
+            Ident {
+                ident: "S",
+                span: #0 bytes(0..0)
+            }
+        ],
+        span: #0 bytes(0..0)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #0 bytes(0..0)
+    }
+]

From f756257fb7a5a6ff9fedd83ef03ed09a34bfef13 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 11 Dec 2018 02:26:31 +0300
Subject: [PATCH 5/6] Do not interpret mismatches from pretty-printed `$crate`
 as token stream invalidation

---
 src/libsyntax/parse/token.rs               |  4 +-
 src/libsyntax/tokenstream.rs               |  4 +-
 src/test/ui/proc-macro/dollar-crate.stderr | 10 ++-
 src/test/ui/proc-macro/dollar-crate.stdout | 92 +++++++++-------------
 4 files changed, 50 insertions(+), 60 deletions(-)

diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index ed7466574596f..badcc4ed8762d 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -633,7 +633,9 @@ impl Token {
             (&Shebang(a), &Shebang(b)) => a == b,
 
             (&Lifetime(a), &Lifetime(b)) => a.name == b.name,
-            (&Ident(a, b), &Ident(c, d)) => a.name == c.name && b == d,
+            (&Ident(a, b), &Ident(c, d)) => b == d && (a.name == c.name ||
+                                                       a.name == keywords::DollarCrate.name() ||
+                                                       c.name == keywords::DollarCrate.name()),
 
             (&Literal(ref a, b), &Literal(ref c, d)) => {
                 b == d && a.probably_equal_for_proc_macro(c)
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index c11ef33f931d8..013ecd3d343c2 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -348,7 +348,9 @@ impl TokenStream {
                 | TokenTree::Token(_, Token::Semi)
                 // The pretty printer collapses whitespace arbitrarily and can
                 // introduce whitespace from `NoDelim`.
-                | TokenTree::Token(_, Token::Whitespace) => false,
+                | TokenTree::Token(_, Token::Whitespace)
+                // The pretty printer can turn `$crate` into `::crate_name`
+                | TokenTree::Token(_, Token::ModSep) => false,
                 _ => true
             }
         }
diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr
index 171562a5aff20..75d3e17802ebd 100644
--- a/src/test/ui/proc-macro/dollar-crate.stderr
+++ b/src/test/ui/proc-macro/dollar-crate.stderr
@@ -2,7 +2,10 @@ error[E0428]: the name `D` is defined multiple times
   --> $DIR/dollar-crate.rs:23:13
    |
 LL |             struct D($crate::S); //~ ERROR the name `D` is defined multiple times
-   |             ^^^^^^^^^^^^^^^^^^^^ `D` redefined here
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |             |
+   |             `D` redefined here
+   |             previous definition of the type `D` here
 ...
 LL |     local!();
    |     --------- in this macro invocation
@@ -13,7 +16,10 @@ error[E0428]: the name `D` is defined multiple times
   --> $DIR/dollar-crate.rs:31:5
    |
 LL |     dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `D` redefined here
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     `D` redefined here
+   |     previous definition of the type `D` here
    |
    = note: `D` must be defined only once in the type namespace of this module
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout
index 8e254854e32e6..c47b3603f41c0 100644
--- a/src/test/ui/proc-macro/dollar-crate.stdout
+++ b/src/test/ui/proc-macro/dollar-crate.stdout
@@ -42,80 +42,80 @@ ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S);
 ATTRIBUTE INPUT: TokenStream [
     Ident {
         ident: "struct",
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     },
     Ident {
         ident: "A",
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
-                ident: "crate",
-                span: #0 bytes(0..0)
+                ident: "$crate",
+                span: #2 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #0 bytes(0..0)
+                span: #2 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #0 bytes(0..0)
+                span: #2 bytes(LO..HI)
             },
             Ident {
                 ident: "S",
-                span: #0 bytes(0..0)
+                span: #2 bytes(LO..HI)
             }
         ],
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     }
 ]
 DERIVE INPUT (PRETTY-PRINTED): struct D(crate::S);
 DERIVE INPUT: TokenStream [
     Ident {
         ident: "struct",
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     },
     Ident {
         ident: "D",
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
-                ident: "crate",
-                span: #0 bytes(0..0)
+                ident: "$crate",
+                span: #2 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #0 bytes(0..0)
+                span: #2 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #0 bytes(0..0)
+                span: #2 bytes(LO..HI)
             },
             Ident {
                 ident: "S",
-                span: #0 bytes(0..0)
+                span: #2 bytes(LO..HI)
             }
         ],
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #0 bytes(0..0)
+        span: #2 bytes(LO..HI)
     }
 ]
 PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ;
@@ -162,99 +162,79 @@ ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(::dollar_crate_external::S);
 ATTRIBUTE INPUT: TokenStream [
     Ident {
         ident: "struct",
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     },
     Ident {
         ident: "A",
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
-            Punct {
-                ch: ':',
-                spacing: Joint,
-                span: #0 bytes(0..0)
-            },
-            Punct {
-                ch: ':',
-                spacing: Alone,
-                span: #0 bytes(0..0)
-            },
             Ident {
-                ident: "dollar_crate_external",
-                span: #0 bytes(0..0)
+                ident: "$crate",
+                span: #10 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #0 bytes(0..0)
+                span: #10 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #0 bytes(0..0)
+                span: #10 bytes(LO..HI)
             },
             Ident {
                 ident: "S",
-                span: #0 bytes(0..0)
+                span: #10 bytes(LO..HI)
             }
         ],
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     }
 ]
 DERIVE INPUT (PRETTY-PRINTED): struct D(::dollar_crate_external::S);
 DERIVE INPUT: TokenStream [
     Ident {
         ident: "struct",
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     },
     Ident {
         ident: "D",
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
-            Punct {
-                ch: ':',
-                spacing: Joint,
-                span: #0 bytes(0..0)
-            },
-            Punct {
-                ch: ':',
-                spacing: Alone,
-                span: #0 bytes(0..0)
-            },
             Ident {
-                ident: "dollar_crate_external",
-                span: #0 bytes(0..0)
+                ident: "$crate",
+                span: #10 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #0 bytes(0..0)
+                span: #10 bytes(LO..HI)
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #0 bytes(0..0)
+                span: #10 bytes(LO..HI)
             },
             Ident {
                 ident: "S",
-                span: #0 bytes(0..0)
+                span: #10 bytes(LO..HI)
             }
         ],
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #0 bytes(0..0)
+        span: #10 bytes(LO..HI)
     }
 ]

From edab6c74923cacb3058fb7942577ad27e7cd32ff Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 18 Dec 2018 03:21:28 +0300
Subject: [PATCH 6/6] Workaround issues with crate loading during
 cross-compilation

---
 src/test/ui/proc-macro/dollar-crate.rs     | 8 +++++++-
 src/test/ui/proc-macro/dollar-crate.stderr | 4 ++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs
index 3f4a01cb2dca9..1460e9a3b2d55 100644
--- a/src/test/ui/proc-macro/dollar-crate.rs
+++ b/src/test/ui/proc-macro/dollar-crate.rs
@@ -1,5 +1,4 @@
 // edition:2018
-// compile-flags:--extern dollar_crate --extern dollar_crate_external
 // aux-build:dollar-crate.rs
 // aux-build:dollar-crate-external.rs
 
@@ -7,9 +6,14 @@
 // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
 // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
 
+extern crate dollar_crate;
+extern crate dollar_crate_external;
+
 type S = u8;
 
 mod local {
+    use crate::dollar_crate;
+
     macro_rules! local {
         () => {
             dollar_crate::m! {
@@ -28,6 +32,8 @@ mod local {
 }
 
 mod external {
+    use crate::dollar_crate_external;
+
     dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
 }
 
diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr
index 75d3e17802ebd..08de3c7d1a666 100644
--- a/src/test/ui/proc-macro/dollar-crate.stderr
+++ b/src/test/ui/proc-macro/dollar-crate.stderr
@@ -1,5 +1,5 @@
 error[E0428]: the name `D` is defined multiple times
-  --> $DIR/dollar-crate.rs:23:13
+  --> $DIR/dollar-crate.rs:27:13
    |
 LL |             struct D($crate::S); //~ ERROR the name `D` is defined multiple times
    |             ^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     local!();
    = note: `D` must be defined only once in the type namespace of this module
 
 error[E0428]: the name `D` is defined multiple times
-  --> $DIR/dollar-crate.rs:31:5
+  --> $DIR/dollar-crate.rs:37:5
    |
 LL |     dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^