Rollup merge of #62393 - petrochenkov:notto-disu, r=Mark-Simulacrum
Fix pretty-printing of `$crate` (take 4) Pretty-print `$crate` as `crate` or `crate_name` in unstructured tokens like `a $crate c` in `foo!(a $crate c)`, but only if those tokens are printed as a part of AST pretty-printing, rather than as a standalone token stream. Fixes https://github.com/rust-lang/rust/issues/62325 Previous iterations - https://github.com/rust-lang/rust/pull/56647, https://github.com/rust-lang/rust/pull/57155, https://github.com/rust-lang/rust/pull/57915.
This commit is contained in:
commit
fe26fc9a1c
@ -758,7 +758,10 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
|
||||
let def_id = self.macro_defs[&expansion];
|
||||
let def_id = match self.macro_defs.get(&expansion) {
|
||||
Some(def_id) => *def_id,
|
||||
None => return self.graph_root,
|
||||
};
|
||||
if let Some(id) = self.definitions.as_local_node_id(def_id) {
|
||||
self.local_macro_def_scopes[&id]
|
||||
} else if def_id.krate == CrateNum::BuiltinMacros {
|
||||
|
@ -17,12 +17,11 @@ use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, Determinacy};
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension};
|
||||
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ext::hygiene::{self, Mark};
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name};
|
||||
use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES};
|
||||
use syntax::symbol::{Symbol, kw, sym};
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::Applicability;
|
||||
@ -146,24 +145,14 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
mark
|
||||
}
|
||||
|
||||
fn resolve_dollar_crates(&mut self, fragment: &AstFragment) {
|
||||
struct ResolveDollarCrates<'a, 'b> {
|
||||
resolver: &'a mut Resolver<'b>
|
||||
}
|
||||
impl<'a> Visitor<'a> for ResolveDollarCrates<'a, '_> {
|
||||
fn visit_ident(&mut self, ident: Ident) {
|
||||
if ident.name == kw::DollarCrate {
|
||||
let name = match self.resolver.resolve_crate_root(ident).kind {
|
||||
ModuleKind::Def(.., name) if name != kw::Invalid => name,
|
||||
_ => kw::Crate,
|
||||
};
|
||||
ident.span.ctxt().set_dollar_crate_name(name);
|
||||
}
|
||||
fn resolve_dollar_crates(&mut self) {
|
||||
hygiene::update_dollar_crate_names(|ctxt| {
|
||||
let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
|
||||
match self.resolve_crate_root(ident).kind {
|
||||
ModuleKind::Def(.., name) if name != kw::Invalid => name,
|
||||
_ => kw::Crate,
|
||||
}
|
||||
fn visit_mac(&mut self, _: &ast::Mac) {}
|
||||
}
|
||||
|
||||
fragment.visit_with(&mut ResolveDollarCrates { resolver: self });
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
|
||||
|
@ -701,7 +701,7 @@ pub trait Resolver {
|
||||
|
||||
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
|
||||
|
||||
fn resolve_dollar_crates(&mut self, fragment: &AstFragment);
|
||||
fn resolve_dollar_crates(&mut self);
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
|
||||
derives: &[Mark]);
|
||||
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
|
||||
|
@ -429,7 +429,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[Mark])
|
||||
-> (AstFragment, Vec<Invocation>) {
|
||||
// Resolve `$crate`s in the fragment for pretty-printing.
|
||||
self.cx.resolver.resolve_dollar_crates(&fragment);
|
||||
self.cx.resolver.resolve_dollar_crates();
|
||||
|
||||
let invocations = {
|
||||
let mut collector = InvocationCollector {
|
||||
|
@ -18,7 +18,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree};
|
||||
|
||||
use rustc_target::spec::abi::{self, Abi};
|
||||
use syntax_pos::{self, BytePos};
|
||||
use syntax_pos::{DUMMY_SP, FileName};
|
||||
use syntax_pos::{DUMMY_SP, FileName, Span};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::io::Read;
|
||||
@ -181,7 +181,46 @@ pub fn literal_to_string(lit: token::Lit) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
fn ident_to_string(ident: ast::Ident, is_raw: bool) -> String {
|
||||
ident_to_string_ext(ident.name, is_raw, Some(ident.span))
|
||||
}
|
||||
|
||||
// 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 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.
|
||||
// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing,
|
||||
// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents,
|
||||
// so we should not perform this lossy conversion if the top level call to the pretty-printer was
|
||||
// done for a token stream or a single token.
|
||||
fn ident_to_string_ext(
|
||||
name: ast::Name, is_raw: bool, convert_dollar_crate: Option<Span>
|
||||
) -> String {
|
||||
if is_raw {
|
||||
format!("r#{}", name)
|
||||
} else {
|
||||
if name == kw::DollarCrate {
|
||||
if let Some(span) = convert_dollar_crate {
|
||||
let converted = span.ctxt().dollar_crate_name();
|
||||
return if converted.is_path_segment_keyword() {
|
||||
converted.to_string()
|
||||
} else {
|
||||
format!("::{}", converted)
|
||||
}
|
||||
}
|
||||
}
|
||||
name.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn token_kind_to_string(tok: &TokenKind) -> String {
|
||||
token_kind_to_string_ext(tok, None)
|
||||
}
|
||||
|
||||
fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String {
|
||||
match *tok {
|
||||
token::Eq => "=".to_string(),
|
||||
token::Lt => "<".to_string(),
|
||||
@ -227,8 +266,7 @@ pub fn token_kind_to_string(tok: &TokenKind) -> String {
|
||||
token::Literal(lit) => literal_to_string(lit),
|
||||
|
||||
/* Name components */
|
||||
token::Ident(s, false) => s.to_string(),
|
||||
token::Ident(s, true) => format!("r#{}", s),
|
||||
token::Ident(s, is_raw) => ident_to_string_ext(s, is_raw, convert_dollar_crate),
|
||||
token::Lifetime(s) => s.to_string(),
|
||||
|
||||
/* Other */
|
||||
@ -243,7 +281,12 @@ pub fn token_kind_to_string(tok: &TokenKind) -> String {
|
||||
}
|
||||
|
||||
pub fn token_to_string(token: &Token) -> String {
|
||||
token_kind_to_string(&token.kind)
|
||||
token_to_string_ext(token, false)
|
||||
}
|
||||
|
||||
fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
|
||||
let convert_dollar_crate = if convert_dollar_crate { Some(token.span) } else { None };
|
||||
token_kind_to_string_ext(&token.kind, convert_dollar_crate)
|
||||
}
|
||||
|
||||
crate fn nonterminal_to_string(nt: &Nonterminal) -> String {
|
||||
@ -256,9 +299,8 @@ crate fn nonterminal_to_string(nt: &Nonterminal) -> String {
|
||||
token::NtBlock(ref e) => block_to_string(e),
|
||||
token::NtStmt(ref e) => stmt_to_string(e),
|
||||
token::NtPat(ref e) => pat_to_string(e),
|
||||
token::NtIdent(e, false) => ident_to_string(e),
|
||||
token::NtIdent(e, true) => format!("r#{}", ident_to_string(e)),
|
||||
token::NtLifetime(e) => ident_to_string(e),
|
||||
token::NtIdent(e, is_raw) => ident_to_string(e, is_raw),
|
||||
token::NtLifetime(e) => e.to_string(),
|
||||
token::NtLiteral(ref e) => expr_to_string(e),
|
||||
token::NtTT(ref tree) => tt_to_string(tree.clone()),
|
||||
token::NtImplItem(ref e) => impl_item_to_string(e),
|
||||
@ -293,15 +335,15 @@ pub fn lifetime_to_string(lt: &ast::Lifetime) -> String {
|
||||
}
|
||||
|
||||
pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
|
||||
to_string(|s| s.print_tt(tt))
|
||||
to_string(|s| s.print_tt(tt, false))
|
||||
}
|
||||
|
||||
pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String {
|
||||
to_string(|s| s.print_tts(tts.iter().cloned().collect()))
|
||||
tokens_to_string(tts.iter().cloned().collect())
|
||||
}
|
||||
|
||||
pub fn tokens_to_string(tokens: TokenStream) -> String {
|
||||
to_string(|s| s.print_tts(tokens))
|
||||
to_string(|s| s.print_tts_ext(tokens, false))
|
||||
}
|
||||
|
||||
pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
|
||||
@ -344,10 +386,6 @@ pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
|
||||
to_string(|s| s.print_path_segment(p, false))
|
||||
}
|
||||
|
||||
pub fn ident_to_string(id: ast::Ident) -> String {
|
||||
to_string(|s| s.print_ident(id))
|
||||
}
|
||||
|
||||
pub fn vis_to_string(v: &ast::Visibility) -> String {
|
||||
to_string(|s| s.print_visibility(v))
|
||||
}
|
||||
@ -629,11 +667,7 @@ pub trait PrintState<'a> {
|
||||
self.writer().word("::");
|
||||
}
|
||||
if segment.ident.name != kw::PathRoot {
|
||||
if segment.ident.name == kw::DollarCrate {
|
||||
self.print_dollar_crate(segment.ident);
|
||||
} else {
|
||||
self.writer().word(segment.ident.as_str().to_string());
|
||||
}
|
||||
self.writer().word(ident_to_string(segment.ident, segment.ident.is_raw_guess()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -707,10 +741,10 @@ pub trait PrintState<'a> {
|
||||
/// appropriate macro, transcribe back into the grammar we just parsed from,
|
||||
/// and then pretty-print the resulting AST nodes (so, e.g., we print
|
||||
/// expression arguments as expressions). It can be done! I think.
|
||||
fn print_tt(&mut self, tt: tokenstream::TokenTree) {
|
||||
fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) {
|
||||
match tt {
|
||||
TokenTree::Token(ref token) => {
|
||||
self.writer().word(token_to_string(&token));
|
||||
self.writer().word(token_to_string_ext(&token, convert_dollar_crate));
|
||||
match token.kind {
|
||||
token::DocComment(..) => {
|
||||
self.writer().hardbreak()
|
||||
@ -729,12 +763,16 @@ pub trait PrintState<'a> {
|
||||
}
|
||||
|
||||
fn print_tts(&mut self, tts: tokenstream::TokenStream) {
|
||||
self.print_tts_ext(tts, true)
|
||||
}
|
||||
|
||||
fn print_tts_ext(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) {
|
||||
self.ibox(0);
|
||||
for (i, tt) in tts.into_trees().enumerate() {
|
||||
if i != 0 {
|
||||
self.writer().space();
|
||||
}
|
||||
self.print_tt(tt);
|
||||
self.print_tt(tt, convert_dollar_crate);
|
||||
}
|
||||
self.end();
|
||||
}
|
||||
@ -744,21 +782,6 @@ pub trait PrintState<'a> {
|
||||
}
|
||||
|
||||
fn nbsp(&mut self) { 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) {
|
||||
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().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PrintState<'a> for State<'a> {
|
||||
@ -2287,11 +2310,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
crate fn print_ident(&mut self, ident: ast::Ident) {
|
||||
if ident.is_raw_guess() {
|
||||
self.s.word(format!("r#{}", ident));
|
||||
} else {
|
||||
self.s.word(ident.as_str().to_string());
|
||||
}
|
||||
self.s.word(ident_to_string(ident, ident.is_raw_guess()));
|
||||
self.ann.post(self, AnnNode::Ident(&ident))
|
||||
}
|
||||
|
||||
@ -2322,11 +2341,7 @@ impl<'a> State<'a> {
|
||||
segment: &ast::PathSegment,
|
||||
colons_before_params: bool) {
|
||||
if segment.ident.name != kw::PathRoot {
|
||||
if segment.ident.name == kw::DollarCrate {
|
||||
self.print_dollar_crate(segment.ident);
|
||||
} else {
|
||||
self.print_ident(segment.ident);
|
||||
}
|
||||
self.print_ident(segment.ident);
|
||||
if let Some(ref args) = segment.args {
|
||||
self.print_generic_args(args, colons_before_params);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ use crate::symbol::{kw, Symbol};
|
||||
use serialize::{Encodable, Decodable, Encoder, Decoder};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::{fmt, mem};
|
||||
use std::fmt;
|
||||
|
||||
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
|
||||
@ -387,6 +387,23 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
|
||||
HygieneData::with(|data| data.walk_chain(span, to))
|
||||
}
|
||||
|
||||
pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
|
||||
// The new contexts that need updating are at the end of the list and have `$crate` as a name.
|
||||
let (len, to_update) = HygieneData::with(|data| (
|
||||
data.syntax_contexts.len(),
|
||||
data.syntax_contexts.iter().rev()
|
||||
.take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate).count()
|
||||
));
|
||||
// The callback must be called from outside of the `HygieneData` lock,
|
||||
// since it will try to acquire it too.
|
||||
let range_to_update = len - to_update .. len;
|
||||
let names: Vec<_> =
|
||||
range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect();
|
||||
HygieneData::with(|data| range_to_update.zip(names.into_iter()).for_each(|(idx, name)| {
|
||||
data.syntax_contexts[idx].dollar_crate_name = name;
|
||||
}))
|
||||
}
|
||||
|
||||
impl SyntaxContext {
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
@ -614,17 +631,6 @@ impl SyntaxContext {
|
||||
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 == kw::DollarCrate,
|
||||
"$crate name is reset for a syntax context");
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SyntaxContext {
|
||||
|
@ -14,3 +14,9 @@ macro_rules! external {
|
||||
struct D($crate::S);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! issue_62325 { () => {
|
||||
#[print_attr]
|
||||
struct B(identity!($crate::S));
|
||||
}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ;
|
||||
PRINT-BANG INPUT (DISPLAY): struct M ( crate :: S ) ;
|
||||
PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
},
|
||||
]
|
||||
PRINT-ATTR INPUT (DISPLAY): struct A(crate::S);
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ;
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( crate :: S ) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
|
27
src/test/ui/proc-macro/dollar-crate-issue-62325.rs
Normal file
27
src/test/ui/proc-macro/dollar-crate-issue-62325.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// check-pass
|
||||
// edition:2018
|
||||
// aux-build:test-macros.rs
|
||||
// aux-build:dollar-crate-external.rs
|
||||
|
||||
// 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)"
|
||||
|
||||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate test_macros;
|
||||
extern crate dollar_crate_external;
|
||||
|
||||
type S = u8;
|
||||
|
||||
macro_rules! m { () => {
|
||||
#[print_attr]
|
||||
struct A(identity!($crate::S));
|
||||
}}
|
||||
|
||||
m!();
|
||||
|
||||
dollar_crate_external::issue_62325!();
|
||||
|
||||
fn main() {}
|
112
src/test/ui/proc-macro/dollar-crate-issue-62325.stdout
Normal file
112
src/test/ui/proc-macro/dollar-crate-issue-62325.stdout
Normal file
@ -0,0 +1,112 @@
|
||||
PRINT-ATTR INPUT (DISPLAY): struct A(identity!(crate :: S));
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( identity ! ( crate :: S ) ) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: #2 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "A",
|
||||
span: #2 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "identity",
|
||||
span: #2 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: '!',
|
||||
spacing: Alone,
|
||||
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),
|
||||
},
|
||||
],
|
||||
span: #2 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ';',
|
||||
spacing: Alone,
|
||||
span: #2 bytes(LO..HI),
|
||||
},
|
||||
]
|
||||
PRINT-ATTR INPUT (DISPLAY): struct B(identity!(::dollar_crate_external :: S));
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct B ( identity ! ( ::dollar_crate_external :: S ) ) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "B",
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "identity",
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: '!',
|
||||
spacing: Alone,
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "$crate",
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Joint,
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "S",
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ';',
|
||||
spacing: Alone,
|
||||
span: #7 bytes(LO..HI),
|
||||
},
|
||||
]
|
@ -1,4 +1,4 @@
|
||||
PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ;
|
||||
PRINT-BANG INPUT (DISPLAY): struct M ( crate :: S ) ;
|
||||
PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
},
|
||||
]
|
||||
PRINT-ATTR INPUT (DISPLAY): struct A(crate::S);
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ;
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( crate :: S ) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
@ -80,7 +80,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
},
|
||||
]
|
||||
PRINT-DERIVE INPUT (DISPLAY): struct D(crate::S);
|
||||
PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( $crate :: S ) ;
|
||||
PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( crate :: S ) ;
|
||||
PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
@ -120,7 +120,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||
span: #2 bytes(LO..HI),
|
||||
},
|
||||
]
|
||||
PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ;
|
||||
PRINT-BANG INPUT (DISPLAY): struct M ( ::dollar_crate_external :: S ) ;
|
||||
PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
@ -161,7 +161,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
},
|
||||
]
|
||||
PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S);
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ;
|
||||
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( ::dollar_crate_external :: S ) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
@ -202,7 +202,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
},
|
||||
]
|
||||
PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S);
|
||||
PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( $crate :: S ) ;
|
||||
PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( ::dollar_crate_external :: S ) ;
|
||||
PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
|
Loading…
x
Reference in New Issue
Block a user