Skip to content

Commit e8ca35e

Browse files
committed
Auto merge of #57155 - petrochenkov:dcrate3, r=dtolnay
Resolve `$crate`s for pretty-printing at more appropriate time Doing it in `BuildReducedGraphVisitor` wasn't a good idea, identifiers wasn't actually visited half of the time. As a result some `$crate`s weren't resolved and were therefore pretty-printed as `$crate` literally, which turns into two tokens during re-parsing of the pretty-printed text. Now we are visiting and resolving `$crate` identifiers in an item right before sending that item to a proc macro attribute or derive. Fixes #57089
2 parents f8caa32 + e40d7d9 commit e8ca35e

File tree

7 files changed

+154
-13
lines changed

7 files changed

+154
-13
lines changed

src/librustc_resolve/build_reduced_graph.rs

-11
Original file line numberDiff line numberDiff line change
@@ -1025,15 +1025,4 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
10251025
}
10261026
visit::walk_attribute(self, attr);
10271027
}
1028-
1029-
fn visit_ident(&mut self, ident: Ident) {
1030-
if ident.name == keywords::DollarCrate.name() {
1031-
let name = match self.resolver.resolve_crate_root(ident).kind {
1032-
ModuleKind::Def(_, name) if name != keywords::Invalid.name() => name,
1033-
_ => keywords::Crate.name(),
1034-
};
1035-
ident.span.ctxt().set_dollar_crate_name(name);
1036-
}
1037-
visit::walk_ident(self, ident);
1038-
}
10391028
}

src/librustc_resolve/macros.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
22
use {CrateLint, Resolver, ResolutionError, ScopeSet, Weak};
3-
use {Module, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
3+
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
44
use {is_known_tool, resolve_error};
55
use ModuleOrUniformRoot;
66
use Namespace::*;
@@ -15,12 +15,13 @@ use syntax::ast::{self, Ident};
1515
use syntax::attr;
1616
use syntax::errors::DiagnosticBuilder;
1717
use syntax::ext::base::{self, Determinacy};
18-
use syntax::ext::base::{MacroKind, SyntaxExtension};
18+
use syntax::ext::base::{Annotatable, MacroKind, SyntaxExtension};
1919
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
2020
use syntax::ext::hygiene::{self, Mark};
2121
use syntax::ext::tt::macro_rules;
2222
use syntax::feature_gate::{feature_err, is_builtin_attr_name, GateIssue};
2323
use syntax::symbol::{Symbol, keywords};
24+
use syntax::visit::Visitor;
2425
use syntax::util::lev_distance::find_best_match_for_name;
2526
use syntax_pos::{Span, DUMMY_SP};
2627
use errors::Applicability;
@@ -126,6 +127,26 @@ impl<'a> base::Resolver for Resolver<'a> {
126127
mark
127128
}
128129

130+
fn resolve_dollar_crates(&mut self, annotatable: &Annotatable) {
131+
pub struct ResolveDollarCrates<'a, 'b: 'a> {
132+
pub resolver: &'a mut Resolver<'b>,
133+
}
134+
impl<'a> Visitor<'a> for ResolveDollarCrates<'a, '_> {
135+
fn visit_ident(&mut self, ident: Ident) {
136+
if ident.name == keywords::DollarCrate.name() {
137+
let name = match self.resolver.resolve_crate_root(ident).kind {
138+
ModuleKind::Def(_, name) if name != keywords::Invalid.name() => name,
139+
_ => keywords::Crate.name(),
140+
};
141+
ident.span.ctxt().set_dollar_crate_name(name);
142+
}
143+
}
144+
fn visit_mac(&mut self, _: &ast::Mac) {}
145+
}
146+
147+
annotatable.visit_with(&mut ResolveDollarCrates { resolver: self });
148+
}
149+
129150
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
130151
derives: &[Mark]) {
131152
let invocation = self.invocations[&mark];

src/libsyntax/ext/base.rs

+14
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use parse::token;
1414
use ptr::P;
1515
use smallvec::SmallVec;
1616
use symbol::{keywords, Ident, Symbol};
17+
use visit::Visitor;
1718
use ThinVec;
1819

1920
use rustc_data_structures::fx::FxHashMap;
@@ -135,6 +136,17 @@ impl Annotatable {
135136
_ => false,
136137
}
137138
}
139+
140+
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
141+
match self {
142+
Annotatable::Item(item) => visitor.visit_item(item),
143+
Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item),
144+
Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item),
145+
Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
146+
Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
147+
Annotatable::Expr(expr) => visitor.visit_expr(expr),
148+
}
149+
}
138150
}
139151

140152
// A more flexible ItemDecorator.
@@ -730,6 +742,7 @@ pub trait Resolver {
730742
fn next_node_id(&mut self) -> ast::NodeId;
731743
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
732744

745+
fn resolve_dollar_crates(&mut self, annotatable: &Annotatable);
733746
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
734747
derives: &[Mark]);
735748
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
@@ -763,6 +776,7 @@ impl Resolver for DummyResolver {
763776
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
764777
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
765778

779+
fn resolve_dollar_crates(&mut self, _annotatable: &Annotatable) {}
766780
fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
767781
_derives: &[Mark]) {}
768782
fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}

src/libsyntax/ext/expand.rs

+4
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
574574
Some(invoc.fragment_kind.expect_from_annotatables(items))
575575
}
576576
AttrProcMacro(ref mac, ..) => {
577+
// Resolve `$crate`s in case we have to go though stringification.
578+
self.cx.resolver.resolve_dollar_crates(&item);
577579
self.gate_proc_macro_attr_item(attr.span, &item);
578580
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
579581
Annotatable::Item(item) => token::NtItem(item),
@@ -915,6 +917,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
915917

916918
match *ext {
917919
ProcMacroDerive(ref ext, ..) => {
920+
// Resolve `$crate`s in case we have to go though stringification.
921+
self.cx.resolver.resolve_dollar_crates(&item);
918922
invoc.expansion_data.mark.set_expn_info(expn_info);
919923
let span = span.with_ctxt(self.cx.backtrace());
920924
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this

src/test/ui/proc-macro/auxiliary/dollar-crate.rs

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
extern crate proc_macro;
77
use proc_macro::TokenStream;
88

9+
#[proc_macro]
10+
pub fn m_empty(input: TokenStream) -> TokenStream {
11+
println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input);
12+
println!("PROC MACRO INPUT: {:#?}", input);
13+
TokenStream::new()
14+
}
15+
916
#[proc_macro]
1017
pub fn m(input: TokenStream) -> TokenStream {
1118
println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// compile-pass
2+
// edition:2018
3+
// aux-build:dollar-crate.rs
4+
5+
// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
6+
// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
7+
// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
8+
9+
extern crate dollar_crate;
10+
11+
type S = u8;
12+
13+
macro_rules! m {
14+
() => {
15+
dollar_crate::m_empty! {
16+
struct M($crate::S);
17+
}
18+
19+
#[dollar_crate::a]
20+
struct A($crate::S);
21+
};
22+
}
23+
24+
m!();
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ;
2+
PROC MACRO INPUT: TokenStream [
3+
Ident {
4+
ident: "struct",
5+
span: #2 bytes(LO..HI)
6+
},
7+
Ident {
8+
ident: "M",
9+
span: #2 bytes(LO..HI)
10+
},
11+
Group {
12+
delimiter: Parenthesis,
13+
stream: TokenStream [
14+
Ident {
15+
ident: "$crate",
16+
span: #2 bytes(LO..HI)
17+
},
18+
Punct {
19+
ch: ':',
20+
spacing: Joint,
21+
span: #2 bytes(LO..HI)
22+
},
23+
Punct {
24+
ch: ':',
25+
spacing: Alone,
26+
span: #2 bytes(LO..HI)
27+
},
28+
Ident {
29+
ident: "S",
30+
span: #2 bytes(LO..HI)
31+
}
32+
],
33+
span: #2 bytes(LO..HI)
34+
},
35+
Punct {
36+
ch: ';',
37+
spacing: Alone,
38+
span: #2 bytes(LO..HI)
39+
}
40+
]
41+
ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S);
42+
ATTRIBUTE INPUT: TokenStream [
43+
Ident {
44+
ident: "struct",
45+
span: #2 bytes(LO..HI)
46+
},
47+
Ident {
48+
ident: "A",
49+
span: #2 bytes(LO..HI)
50+
},
51+
Group {
52+
delimiter: Parenthesis,
53+
stream: TokenStream [
54+
Ident {
55+
ident: "$crate",
56+
span: #2 bytes(LO..HI)
57+
},
58+
Punct {
59+
ch: ':',
60+
spacing: Joint,
61+
span: #2 bytes(LO..HI)
62+
},
63+
Punct {
64+
ch: ':',
65+
spacing: Alone,
66+
span: #2 bytes(LO..HI)
67+
},
68+
Ident {
69+
ident: "S",
70+
span: #2 bytes(LO..HI)
71+
}
72+
],
73+
span: #2 bytes(LO..HI)
74+
},
75+
Punct {
76+
ch: ';',
77+
spacing: Alone,
78+
span: #2 bytes(LO..HI)
79+
}
80+
]

0 commit comments

Comments
 (0)