Reintroduce special pretty-printing for $crate
when it's necessary for proc macros
This commit is contained in:
parent
2bc67da378
commit
69c66286a9
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -39,8 +39,8 @@ pub fn bar() ({
|
||||
|
||||
|
||||
|
||||
((::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
|
||||
|
16
src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
Normal file
16
src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
Normal file
@ -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);
|
||||
};
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
check!();
|
||||
#[dollar_crate::a]
|
||||
struct A($crate::S);
|
||||
|
||||
#[derive(dollar_crate::d)]
|
||||
struct D($crate::S); //~ ERROR the name `D` is defined multiple times
|
||||
};
|
||||
}
|
||||
|
||||
local!();
|
||||
}
|
||||
|
||||
mod external {
|
||||
dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
23
src/test/ui/proc-macro/dollar-crate.stderr
Normal file
23
src/test/ui/proc-macro/dollar-crate.stderr
Normal file
@ -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`.
|
260
src/test/ui/proc-macro/dollar-crate.stdout
Normal file
260
src/test/ui/proc-macro/dollar-crate.stdout
Normal file
@ -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)
|
||||
}
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user