From c0adb05d340a69f416b98a7daa663188a3a5be0f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 21 Apr 2018 21:33:20 +0300 Subject: [PATCH 1/6] proc_macro: don't use DiagnosticBuilder for building up Diagnostics. --- src/libproc_macro/diagnostic.rs | 46 ++++++++++++++----------------- src/librustc_errors/diagnostic.rs | 2 +- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index 06939a9d1e1c..d178f03ad96e 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -10,7 +10,8 @@ use Span; -use rustc_errors as rustc; +use rustc_errors as errors; +use syntax_pos::MultiSpan; /// An enum representing a diagnostic level. #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] @@ -97,37 +98,32 @@ impl Diagnostic { /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn emit(self) { - ::__internal::with_sess(move |sess, _| { - let handler = &sess.span_diagnostic; - let level = __internal::level_to_internal_level(self.level); - let mut diag = rustc::DiagnosticBuilder::new(handler, level, &*self.message); + let level = self.level.to_internal(); + let mut diag = errors::Diagnostic::new(level, &*self.message); - if let Some(span) = self.span { - diag.set_span(span.0); - } + if let Some(span) = self.span { + diag.set_span(span.0); + } - for child in self.children { - let span = child.span.map(|s| s.0); - let level = __internal::level_to_internal_level(child.level); - diag.sub(level, &*child.message, span); - } + for child in self.children { + let span = child.span.map_or(MultiSpan::new(), |s| s.0.into()); + let level = child.level.to_internal(); + diag.sub(level, &*child.message, span, None); + } - diag.emit(); + ::__internal::with_sess(move |sess, _| { + errors::DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, diag).emit(); }); } } -#[unstable(feature = "proc_macro_internals", issue = "27812")] -#[doc(hidden)] -pub mod __internal { - use super::{Level, rustc}; - - pub fn level_to_internal_level(level: Level) -> rustc::Level { - match level { - Level::Error => rustc::Level::Error, - Level::Warning => rustc::Level::Warning, - Level::Note => rustc::Level::Note, - Level::Help => rustc::Level::Help, +impl Level { + fn to_internal(self) -> errors::Level { + match self { + Level::Error => errors::Level::Error, + Level::Warning => errors::Level::Warning, + Level::Note => errors::Level::Note, + Level::Help => errors::Level::Help, Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive") } } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index d079102a4ba0..b1578b697bb8 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -379,7 +379,7 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. - pub(crate) fn sub(&mut self, + pub fn sub(&mut self, level: Level, message: &str, span: MultiSpan, From d10d0b3e9eb5c72b651c52b6fd38f1db20589b47 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 21 Apr 2018 22:16:55 +0300 Subject: [PATCH 2/6] proc_macro: don't try to reflect literals in quasi-quoting. --- src/libproc_macro/lib.rs | 2 +- src/libproc_macro/quote.rs | 109 +++++-------------------------------- 2 files changed, 16 insertions(+), 95 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f5a7c88a1b71..ea4ca03a0a1f 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -1364,7 +1364,7 @@ impl TokenTree { #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] pub mod __internal { - pub use quote::{LiteralKind, SpannedSymbol, Quoter, unquote}; + pub use quote::{Quoter, unquote}; use std::cell::Cell; use std::ptr; diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index 73a66640c59d..8ae1d7b8525c 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -17,8 +17,6 @@ use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree}; use syntax::ext::base::{ExtCtxt, ProcMacro}; -use syntax::parse::token; -use syntax::symbol::Symbol; use syntax::tokenstream; /// This is the actual quote!() proc macro @@ -42,6 +40,7 @@ macro_rules! quote_tok { (,) => { tt2ts!(Punct::new(',', Spacing::Alone)) }; (.) => { tt2ts!(Punct::new('.', Spacing::Alone)) }; (:) => { tt2ts!(Punct::new(':', Spacing::Alone)) }; + (;) => { tt2ts!(Punct::new(';', Spacing::Alone)) }; (|) => { tt2ts!(Punct::new('|', Spacing::Alone)) }; (::) => { [ @@ -61,6 +60,7 @@ macro_rules! quote_tok { (_) => { tt2ts!(Punct::new('_', Spacing::Alone)) }; (0) => { tt2ts!(Literal::i8_unsuffixed(0)) }; (&) => { tt2ts!(Punct::new('&', Spacing::Alone)) }; + (=) => { tt2ts!(Punct::new('=', Spacing::Alone)) }; ($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) }; } @@ -92,15 +92,6 @@ impl ProcMacro for Quoter { } } -impl Quote for Option { - fn quote(self) -> TokenStream { - match self { - Some(t) => quote!(Some((quote t))), - None => quote!(None), - } - } -} - impl Quote for TokenStream { fn quote(self) -> TokenStream { if self.is_empty() { @@ -194,93 +185,23 @@ impl Quote for Span { } } -macro_rules! literals { - ($($i:ident),*; $($raw:ident),*) => { - pub struct SpannedSymbol { - sym: Symbol, - span: Span, - } - - impl SpannedSymbol { - pub fn new(string: &str, span: Span) -> SpannedSymbol { - SpannedSymbol { sym: Symbol::intern(string), span } - } - } - - impl Quote for SpannedSymbol { - fn quote(self) -> TokenStream { - quote!(::__internal::SpannedSymbol::new((quote self.sym.as_str()), - (quote self.span))) - } - } - - pub enum LiteralKind { - $($i,)* - $($raw(u16),)* - } - - impl LiteralKind { - pub fn with_contents_and_suffix(self, contents: SpannedSymbol, - suffix: Option) -> Literal { - let sym = contents.sym; - let suffix = suffix.map(|t| t.sym); - match self { - $(LiteralKind::$i => { - Literal { - lit: token::Lit::$i(sym), - suffix, - span: contents.span, - } - })* - $(LiteralKind::$raw(n) => { - Literal { - lit: token::Lit::$raw(sym, n), - suffix, - span: contents.span, - } - })* - } - } - } - - impl Literal { - fn kind_contents_and_suffix(self) -> (LiteralKind, SpannedSymbol, Option) - { - let (kind, contents) = match self.lit { - $(token::Lit::$i(contents) => (LiteralKind::$i, contents),)* - $(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)* - }; - let suffix = self.suffix.map(|sym| SpannedSymbol::new(&sym.as_str(), self.span())); - (kind, SpannedSymbol::new(&contents.as_str(), self.span()), suffix) - } - } - - impl Quote for LiteralKind { - fn quote(self) -> TokenStream { - match self { - $(LiteralKind::$i => quote! { - ::__internal::LiteralKind::$i - },)* - $(LiteralKind::$raw(n) => quote! { - ::__internal::LiteralKind::$raw((quote n)) - },)* - } - } - } - - impl Quote for Literal { - fn quote(self) -> TokenStream { - let (kind, contents, suffix) = self.kind_contents_and_suffix(); - quote! { - (quote kind).with_contents_and_suffix((quote contents), (quote suffix)) - } +impl Quote for Literal { + fn quote(self) -> TokenStream { + quote! {{ + let mut iter = (quote self.to_string()) + .parse::<::TokenStream>() + .unwrap() + .into_iter(); + if let (Some(::TokenTree::Literal(mut lit)), None) = (iter.next(), iter.next()) { + lit.set_span((quote self.span)); + lit + } else { + unreachable!() } - } + }} } } -literals!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw); - impl Quote for Delimiter { fn quote(self) -> TokenStream { macro_rules! gen_match { From 56aaa532781e8591c1c5b50aafa2e64634a2de80 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 22 Apr 2018 03:05:02 +0300 Subject: [PATCH 3/6] proc_macro: clean up the implementation of quasi-quoting. --- src/libproc_macro/lib.rs | 14 +- src/libproc_macro/quote.rs | 265 ++++++++++----------------- src/librustc_metadata/cstore_impl.rs | 6 +- src/librustc_metadata/lib.rs | 1 + 4 files changed, 101 insertions(+), 185 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index ea4ca03a0a1f..c88a245d3b37 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -145,6 +145,9 @@ impl fmt::Debug for TokenStream { } } +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub use quote::{quote, quote_span}; + /// Creates a token stream containing a single token tree. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl From for TokenStream { @@ -237,7 +240,7 @@ pub mod token_stream { /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. /// -/// This is a dummy macro, the actual implementation is in quote::Quoter +/// This is a dummy macro, the actual implementation is in `quote::quote`.` #[unstable(feature = "proc_macro_quote", issue = "38356")] #[macro_export] macro_rules! quote { () => {} } @@ -246,13 +249,6 @@ macro_rules! quote { () => {} } #[doc(hidden)] mod quote; -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -#[unstable(feature = "proc_macro_quote", issue = "38356")] -pub fn quote_span(span: Span) -> TokenStream { - quote::Quote::quote(span) -} - /// A region of source code, along with macro expansion information. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Copy, Clone)] @@ -1364,8 +1360,6 @@ impl TokenTree { #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] pub mod __internal { - pub use quote::{Quoter, unquote}; - use std::cell::Cell; use std::ptr; diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index 8ae1d7b8525c..7ae7b13a1521 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -14,34 +14,26 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree}; - -use syntax::ext::base::{ExtCtxt, ProcMacro}; -use syntax::tokenstream; - -/// This is the actual quote!() proc macro -/// -/// It is manually loaded in CStore::load_macro_untracked -pub struct Quoter; - -pub fn unquote + Clone>(tokens: &T) -> TokenStream { - tokens.clone().into() -} - -pub trait Quote { - fn quote(self) -> TokenStream; -} - -macro_rules! tt2ts { - ($e:expr) => (TokenStream::from(TokenTree::from($e))) -} - -macro_rules! quote_tok { - (,) => { tt2ts!(Punct::new(',', Spacing::Alone)) }; - (.) => { tt2ts!(Punct::new('.', Spacing::Alone)) }; - (:) => { tt2ts!(Punct::new(':', Spacing::Alone)) }; - (;) => { tt2ts!(Punct::new(';', Spacing::Alone)) }; - (|) => { tt2ts!(Punct::new('|', Spacing::Alone)) }; +use {Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +macro_rules! quote_tt { + (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; + ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; + ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; + (,) => { Punct::new(',', Spacing::Alone) }; + (.) => { Punct::new('.', Spacing::Alone) }; + (:) => { Punct::new(':', Spacing::Alone) }; + (;) => { Punct::new(';', Spacing::Alone) }; + (!) => { Punct::new('!', Spacing::Alone) }; + (<) => { Punct::new('<', Spacing::Alone) }; + (>) => { Punct::new('>', Spacing::Alone) }; + (&) => { Punct::new('&', Spacing::Alone) }; + (=) => { Punct::new('=', Spacing::Alone) }; + ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; +} + +macro_rules! quote_ts { + ((@ $($t:tt)*)) => { $($t)* }; (::) => { [ TokenTree::from(Punct::new(':', Spacing::Joint)), @@ -54,57 +46,45 @@ macro_rules! quote_tok { }) .collect::() }; - (!) => { tt2ts!(Punct::new('!', Spacing::Alone)) }; - (<) => { tt2ts!(Punct::new('<', Spacing::Alone)) }; - (>) => { tt2ts!(Punct::new('>', Spacing::Alone)) }; - (_) => { tt2ts!(Punct::new('_', Spacing::Alone)) }; - (0) => { tt2ts!(Literal::i8_unsuffixed(0)) }; - (&) => { tt2ts!(Punct::new('&', Spacing::Alone)) }; - (=) => { tt2ts!(Punct::new('=', Spacing::Alone)) }; - ($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) }; -} - -macro_rules! quote_tree { - ((unquote $($t:tt)*)) => { $($t)* }; - ((quote $($t:tt)*)) => { ($($t)*).quote() }; - (($($t:tt)*)) => { tt2ts!(Group::new(Delimiter::Parenthesis, quote!($($t)*))) }; - ([$($t:tt)*]) => { tt2ts!(Group::new(Delimiter::Bracket, quote!($($t)*))) }; - ({$($t:tt)*}) => { tt2ts!(Group::new(Delimiter::Brace, quote!($($t)*))) }; - ($t:tt) => { quote_tok!($t) }; + ($t:tt) => { TokenTree::from(quote_tt!($t)) }; } +/// Simpler version of the real `quote!` macro, implemented solely +/// through `macro_rules`, for bootstrapping the real implementation +/// (see the `quote` function), which does not have access to the +/// real `quote!` macro due to the `proc_macro` crate not being +/// able to depend on itself. +/// +/// Note: supported tokens are a subset of the real `quote!`, but +/// unquoting is different: instead of `$x`, this uses `(@ expr)`. macro_rules! quote { () => { TokenStream::new() }; ($($t:tt)*) => { - [$(quote_tree!($t),)*].iter() - .cloned() - .flat_map(|x| x.into_iter()) - .collect::() + [ + $(TokenStream::from(quote_ts!($t)),)* + ].iter().cloned().collect::() }; } -impl ProcMacro for Quoter { - fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, - _: ::syntax_pos::Span, - stream: tokenstream::TokenStream) - -> tokenstream::TokenStream { - ::__internal::set_sess(cx, || TokenStream(stream).quote().0) +/// Quote a `TokenStream` into a `TokenStream`. +/// This is the actual `quote!()` proc macro. +/// +/// It is manually loaded in `CStore::load_macro_untracked`. +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub fn quote(stream: TokenStream) -> TokenStream { + if stream.is_empty() { + return quote!(::TokenStream::new()); } -} - -impl Quote for TokenStream { - fn quote(self) -> TokenStream { - if self.is_empty() { - return quote!(::TokenStream::new()); - } - let mut after_dollar = false; - let tokens = self.into_iter().filter_map(|tree| { + let mut after_dollar = false; + let tokens = stream + .into_iter() + .filter_map(|tree| { if after_dollar { after_dollar = false; match tree { TokenTree::Ident(_) => { - let tree = TokenStream::from(tree); - return Some(quote!(::__internal::unquote(&(unquote tree)),)); + return Some(quote!(Into::<::TokenStream>::into( + Clone::clone(&(@ tree))),)); } TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), @@ -116,116 +96,55 @@ impl Quote for TokenStream { } } - Some(quote!(::TokenStream::from((quote tree)),)) - }).flat_map(|t| t.into_iter()).collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!( - [(unquote tokens)].iter() - .cloned() - .flat_map(|x| x.into_iter()) - .collect::<::TokenStream>() - ) - } -} - -impl Quote for TokenTree { - fn quote(self) -> TokenStream { - match self { - TokenTree::Punct(tt) => quote!(::TokenTree::Punct( (quote tt) )), - TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )), - TokenTree::Ident(tt) => quote!(::TokenTree::Ident( (quote tt) )), - TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )), - } - } -} - -impl Quote for char { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::character(self)).into() - } -} - -impl<'a> Quote for &'a str { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::string(self)).into() - } -} - -impl Quote for u16 { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::u16_unsuffixed(self)).into() - } -} - -impl Quote for Group { - fn quote(self) -> TokenStream { - quote!(::Group::new((quote self.delimiter()), (quote self.stream()))) - } -} - -impl Quote for Punct { - fn quote(self) -> TokenStream { - quote!(::Punct::new((quote self.as_char()), (quote self.spacing()))) - } -} - -impl Quote for Ident { - fn quote(self) -> TokenStream { - quote!(::Ident::new((quote self.sym.as_str()), (quote self.span()))) - } -} + Some(quote!(::TokenStream::from((@ match tree { + TokenTree::Punct(tt) => quote!(::TokenTree::Punct(::Punct::new( + (@ TokenTree::from(Literal::character(tt.as_char()))), + (@ match tt.spacing() { + Spacing::Alone => quote!(::Spacing::Alone), + Spacing::Joint => quote!(::Spacing::Joint), + }), + ))), + TokenTree::Group(tt) => quote!(::TokenTree::Group(::Group::new( + (@ match tt.delimiter() { + Delimiter::Parenthesis => quote!(::Delimiter::Parenthesis), + Delimiter::Brace => quote!(::Delimiter::Brace), + Delimiter::Bracket => quote!(::Delimiter::Bracket), + Delimiter::None => quote!(::Delimiter::None), + }), + (@ quote(tt.stream())), + ))), + TokenTree::Ident(tt) => quote!(::TokenTree::Ident(::Ident::new( + (@ TokenTree::from(Literal::string(&tt.to_string()))), + (@ quote_span(tt.span())), + ))), + TokenTree::Literal(tt) => quote!(::TokenTree::Literal({ + let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) + .parse::<::TokenStream>() + .unwrap() + .into_iter(); + if let (Some(::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) + { + lit.set_span((@ quote_span(tt.span()))); + lit + } else { + unreachable!() + } + })) + })),)) + }) + .collect::(); -impl Quote for Span { - fn quote(self) -> TokenStream { - quote!(::Span::def_site()) + if after_dollar { + panic!("unexpected trailing `$` in `quote!`"); } -} - -impl Quote for Literal { - fn quote(self) -> TokenStream { - quote! {{ - let mut iter = (quote self.to_string()) - .parse::<::TokenStream>() - .unwrap() - .into_iter(); - if let (Some(::TokenTree::Literal(mut lit)), None) = (iter.next(), iter.next()) { - lit.set_span((quote self.span)); - lit - } else { - unreachable!() - } - }} - } -} - -impl Quote for Delimiter { - fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match self { - $(Delimiter::$i => { quote!(::Delimiter::$i) })* - } - } - } - gen_match!(Parenthesis, Brace, Bracket, None) - } + quote!([(@ tokens)].iter().cloned().collect::<::TokenStream>()) } -impl Quote for Spacing { - fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match self { - $(Spacing::$i => { quote!(::Spacing::$i) })* - } - } - } - - gen_match!(Alone, Joint) - } +/// Quote a `Span` into a `TokenStream`. +/// This is needed to implement a custom quoter. +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub fn quote_span(_: Span) -> TokenStream { + quote!(::Span::def_site()) } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d50786421476..e3a7918f8c58 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -39,7 +39,6 @@ use syntax::ast; use syntax::attr; use syntax::codemap; use syntax::edition::Edition; -use syntax::ext::base::SyntaxExtension; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{Span, NO_EXPANSION, FileName}; @@ -517,8 +516,11 @@ impl CrateStore for cstore::CStore { return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); } else if data.name == "proc_macro" && self.get_crate_data(id.krate).item_name(id.index) == "quote" { + use syntax::ext::base::SyntaxExtension; + use syntax_ext::proc_macro_impl::BangProcMacro; + let ext = SyntaxExtension::ProcMacro { - expander: Box::new(::proc_macro::__internal::Quoter), + expander: Box::new(BangProcMacro { inner: ::proc_macro::quote }), allow_internal_unstable: true, edition: data.root.edition, }; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 5c9915e94e56..d535c1ef9035 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -19,6 +19,7 @@ #![feature(libc)] #![feature(macro_at_most_once_rep)] #![feature(proc_macro_internals)] +#![feature(proc_macro_quote)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] From e5e29d1a1976ff7d0b39ade8706ca0e3ddebe7a9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 16 Mar 2018 17:04:14 +0200 Subject: [PATCH 4/6] proc_macro: don't expose compiler-internal FileName in public API. --- src/libproc_macro/lib.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index c88a245d3b37..f85235278f87 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -50,6 +50,7 @@ mod diagnostic; pub use diagnostic::{Diagnostic, Level}; use std::{ascii, fmt, iter}; +use std::path::PathBuf; use rustc_data_structures::sync::Lrc; use std::str::FromStr; @@ -421,8 +422,11 @@ impl SourceFile { /// /// [`is_real`]: #method.is_real #[unstable(feature = "proc_macro_span", issue = "38356")] - pub fn path(&self) -> &FileName { - &self.filemap.name + pub fn path(&self) -> PathBuf { + match self.filemap.name { + FileName::Real(ref path) => path.clone(), + _ => PathBuf::from(self.filemap.name.to_string()) + } } /// Returns `true` if this source file is a real source file, and not generated by an external @@ -436,18 +440,12 @@ impl SourceFile { } } -#[unstable(feature = "proc_macro_span", issue = "38356")] -impl AsRef for SourceFile { - fn as_ref(&self) -> &FileName { - self.path() - } -} #[unstable(feature = "proc_macro_span", issue = "38356")] impl fmt::Debug for SourceFile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SourceFile") - .field("path", self.path()) + .field("path", &self.path()) .field("is_real", &self.is_real()) .finish() } @@ -463,13 +461,6 @@ impl PartialEq for SourceFile { #[unstable(feature = "proc_macro_span", issue = "38356")] impl Eq for SourceFile {} -#[unstable(feature = "proc_macro_span", issue = "38356")] -impl PartialEq for SourceFile { - fn eq(&self, other: &FileName) -> bool { - self.as_ref() == other - } -} - /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] From bc2b21cc4e2679191b14ade2511e9015e717da53 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 19 Jul 2018 15:59:08 +0300 Subject: [PATCH 5/6] proc_macro: move some implementation details to a rustc module. --- src/libproc_macro/diagnostic.rs | 12 -- src/libproc_macro/lib.rs | 267 +++-------------------------- src/libproc_macro/rustc.rs | 284 +++++++++++++++++++++++++++++++ src/libsyntax/parse/lexer/mod.rs | 6 - 4 files changed, 305 insertions(+), 264 deletions(-) create mode 100644 src/libproc_macro/rustc.rs diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index d178f03ad96e..51e7647f36cc 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -116,15 +116,3 @@ impl Diagnostic { }); } } - -impl Level { - fn to_internal(self) -> errors::Level { - match self { - Level::Error => errors::Level::Error, - Level::Warning => errors::Level::Warning, - Level::Note => errors::Level::Note, - Level::Help => errors::Level::Help, - Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive") - } - } -} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f85235278f87..f63e3e0e4a6f 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -44,6 +44,10 @@ extern crate syntax_pos; extern crate rustc_errors; extern crate rustc_data_structures; +#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[doc(hidden)] +pub mod rustc; + mod diagnostic; #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] @@ -54,12 +58,10 @@ use std::path::PathBuf; use rustc_data_structures::sync::Lrc; use std::str::FromStr; -use syntax::ast; use syntax::errors::DiagnosticBuilder; use syntax::parse::{self, token}; -use syntax::symbol::{keywords, Symbol}; +use syntax::symbol::Symbol; use syntax::tokenstream; -use syntax::parse::lexer::{self, comments}; use syntax_pos::{FileMap, Pos, FileName}; /// The main type provided by this crate, representing an abstract stream of @@ -784,6 +786,16 @@ impl !Send for Ident {} impl !Sync for 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 @@ -805,26 +817,19 @@ 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 !lexer::is_valid_ident(string) { + if !Ident::is_valid(string) { panic!("`{:?}` is not a valid identifier", string) } - Ident { - sym: Symbol::intern(string), - span, - is_raw: false, - } + Ident::new_maybe_raw(string, span, false) } /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). #[unstable(feature = "proc_macro_raw_ident", issue = "38356")] pub fn new_raw(string: &str, span: Span) -> Ident { - let mut ident = Ident::new(string, span); - if ident.sym == keywords::Underscore.name() || - ast::Ident::with_empty_ctxt(ident.sym).is_path_segment_keyword() { - panic!("`{:?}` is not a valid raw identifier", string) + if !Ident::is_valid(string) { + panic!("`{:?}` is not a valid identifier", string) } - ident.is_raw = true; - ident + Ident::new_maybe_raw(string, span, true) } /// Returns the span of this `Ident`, encompassing the entire string returned @@ -861,7 +866,7 @@ impl fmt::Display for Ident { #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Literal { lit: token::Lit, - suffix: Option, + suffix: Option, span: Span, } @@ -1109,236 +1114,6 @@ impl fmt::Display for Literal { } } -impl Delimiter { - fn from_internal(delim: token::DelimToken) -> Delimiter { - match delim { - token::Paren => Delimiter::Parenthesis, - token::Brace => Delimiter::Brace, - token::Bracket => Delimiter::Bracket, - token::NoDelim => Delimiter::None, - } - } - - fn to_internal(self) -> token::DelimToken { - match self { - Delimiter::Parenthesis => token::Paren, - Delimiter::Brace => token::Brace, - Delimiter::Bracket => token::Bracket, - Delimiter::None => token::NoDelim, - } - } -} - -impl TokenTree { - fn from_internal(stream: tokenstream::TokenStream, stack: &mut Vec) - -> TokenTree { - use syntax::parse::token::*; - - let (tree, is_joint) = stream.as_tree(); - let (span, token) = match tree { - tokenstream::TokenTree::Token(span, token) => (span, token), - tokenstream::TokenTree::Delimited(span, delimed) => { - let delimiter = Delimiter::from_internal(delimed.delim); - let mut g = Group::new(delimiter, TokenStream(delimed.tts.into())); - g.set_span(Span(span)); - return g.into() - } - }; - - let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone }; - macro_rules! tt { - ($e:expr) => ({ - let mut x = TokenTree::from($e); - x.set_span(Span(span)); - x - }) - } - macro_rules! op { - ($a:expr) => (tt!(Punct::new($a, op_kind))); - ($a:expr, $b:expr) => ({ - stack.push(tt!(Punct::new($b, op_kind))); - tt!(Punct::new($a, Spacing::Joint)) - }); - ($a:expr, $b:expr, $c:expr) => ({ - stack.push(tt!(Punct::new($c, op_kind))); - stack.push(tt!(Punct::new($b, Spacing::Joint))); - tt!(Punct::new($a, Spacing::Joint)) - }) - } - - match token { - Eq => op!('='), - Lt => op!('<'), - Le => op!('<', '='), - EqEq => op!('=', '='), - Ne => op!('!', '='), - Ge => op!('>', '='), - Gt => op!('>'), - AndAnd => op!('&', '&'), - OrOr => op!('|', '|'), - Not => op!('!'), - Tilde => op!('~'), - BinOp(Plus) => op!('+'), - BinOp(Minus) => op!('-'), - BinOp(Star) => op!('*'), - BinOp(Slash) => op!('/'), - BinOp(Percent) => op!('%'), - BinOp(Caret) => op!('^'), - BinOp(And) => op!('&'), - BinOp(Or) => op!('|'), - BinOp(Shl) => op!('<', '<'), - BinOp(Shr) => op!('>', '>'), - BinOpEq(Plus) => op!('+', '='), - BinOpEq(Minus) => op!('-', '='), - BinOpEq(Star) => op!('*', '='), - BinOpEq(Slash) => op!('/', '='), - BinOpEq(Percent) => op!('%', '='), - BinOpEq(Caret) => op!('^', '='), - BinOpEq(And) => op!('&', '='), - BinOpEq(Or) => op!('|', '='), - BinOpEq(Shl) => op!('<', '<', '='), - BinOpEq(Shr) => op!('>', '>', '='), - At => op!('@'), - Dot => op!('.'), - DotDot => op!('.', '.'), - DotDotDot => op!('.', '.', '.'), - DotDotEq => op!('.', '.', '='), - Comma => op!(','), - Semi => op!(';'), - Colon => op!(':'), - ModSep => op!(':', ':'), - RArrow => op!('-', '>'), - LArrow => op!('<', '-'), - FatArrow => op!('=', '>'), - Pound => op!('#'), - Dollar => op!('$'), - Question => op!('?'), - SingleQuote => op!('\''), - - Ident(ident, false) => { - tt!(self::Ident::new(&ident.as_str(), Span(span))) - } - Ident(ident, true) => { - tt!(self::Ident::new_raw(&ident.as_str(), Span(span))) - } - Lifetime(ident) => { - let ident = ident.without_first_quote(); - stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span)))); - tt!(Punct::new('\'', Spacing::Joint)) - } - Literal(lit, suffix) => tt!(self::Literal { lit, suffix, span: Span(span) }), - DocComment(c) => { - let style = comments::doc_comment_style(&c.as_str()); - let stripped = comments::strip_doc_comment_decoration(&c.as_str()); - let stream = vec![ - tt!(self::Ident::new("doc", Span(span))), - tt!(Punct::new('=', Spacing::Alone)), - tt!(self::Literal::string(&stripped)), - ].into_iter().collect(); - stack.push(tt!(Group::new(Delimiter::Bracket, stream))); - if style == ast::AttrStyle::Inner { - stack.push(tt!(Punct::new('!', Spacing::Alone))); - } - tt!(Punct::new('#', Spacing::Alone)) - } - - Interpolated(_) => { - __internal::with_sess(|sess, _| { - let tts = token.interpolated_to_tokenstream(sess, span); - tt!(Group::new(Delimiter::None, TokenStream(tts))) - }) - } - - DotEq => op!('.', '='), - OpenDelim(..) | CloseDelim(..) => unreachable!(), - Whitespace | Comment | Shebang(..) | Eof => unreachable!(), - } - } - - fn to_internal(self) -> tokenstream::TokenStream { - use syntax::parse::token::*; - use syntax::tokenstream::{TokenTree, Delimited}; - - let (ch, kind, span) = match self { - self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()), - self::TokenTree::Group(tt) => { - return TokenTree::Delimited(tt.span.0, Delimited { - delim: tt.delimiter.to_internal(), - tts: tt.stream.0.into(), - }).into(); - }, - self::TokenTree::Ident(tt) => { - let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw); - return TokenTree::Token(tt.span.0, token).into(); - } - self::TokenTree::Literal(self::Literal { - lit: Lit::Integer(ref a), - suffix, - span, - }) - if a.as_str().starts_with("-") => - { - let minus = BinOp(BinOpToken::Minus); - let integer = Symbol::intern(&a.as_str()[1..]); - let integer = Literal(Lit::Integer(integer), suffix); - let a = TokenTree::Token(span.0, minus); - let b = TokenTree::Token(span.0, integer); - return vec![a, b].into_iter().collect() - } - self::TokenTree::Literal(self::Literal { - lit: Lit::Float(ref a), - suffix, - span, - }) - if a.as_str().starts_with("-") => - { - let minus = BinOp(BinOpToken::Minus); - let float = Symbol::intern(&a.as_str()[1..]); - let float = Literal(Lit::Float(float), suffix); - let a = TokenTree::Token(span.0, minus); - let b = TokenTree::Token(span.0, float); - return vec![a, b].into_iter().collect() - } - self::TokenTree::Literal(tt) => { - let token = Literal(tt.lit, tt.suffix); - return TokenTree::Token(tt.span.0, token).into() - } - }; - - let token = match ch { - '=' => Eq, - '<' => Lt, - '>' => Gt, - '!' => Not, - '~' => Tilde, - '+' => BinOp(Plus), - '-' => BinOp(Minus), - '*' => BinOp(Star), - '/' => BinOp(Slash), - '%' => BinOp(Percent), - '^' => BinOp(Caret), - '&' => BinOp(And), - '|' => BinOp(Or), - '@' => At, - '.' => Dot, - ',' => Comma, - ';' => Semi, - ':' => Colon, - '#' => Pound, - '$' => Dollar, - '?' => Question, - '\'' => SingleQuote, - _ => unreachable!(), - }; - - let tree = TokenTree::Token(span.0, token); - match kind { - Spacing::Alone => tree.into(), - Spacing::Joint => tree.joint(), - } - } -} - /// Permanently unstable internal implementation details of this crate. This /// should not be used. /// diff --git a/src/libproc_macro/rustc.rs b/src/libproc_macro/rustc.rs new file mode 100644 index 000000000000..a54c695f6376 --- /dev/null +++ b/src/libproc_macro/rustc.rs @@ -0,0 +1,284 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {Delimiter, Level, Spacing, Span, __internal}; +use {Group, Ident, Literal, Punct, TokenTree}; + +use rustc_errors as errors; +use syntax::ast; +use syntax::parse::lexer::comments; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::symbol::{keywords, Symbol}; + +impl Ident { + pub(crate) fn new_maybe_raw(string: &str, span: Span, is_raw: bool) -> 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 } + } +} + +impl Delimiter { + pub(crate) fn from_internal(delim: token::DelimToken) -> Delimiter { + match delim { + token::Paren => Delimiter::Parenthesis, + token::Brace => Delimiter::Brace, + token::Bracket => Delimiter::Bracket, + token::NoDelim => Delimiter::None, + } + } + + pub(crate) fn to_internal(self) -> token::DelimToken { + match self { + Delimiter::Parenthesis => token::Paren, + Delimiter::Brace => token::Brace, + Delimiter::Bracket => token::Bracket, + Delimiter::None => token::NoDelim, + } + } +} + +impl TokenTree { + pub(crate) fn from_internal( + stream: tokenstream::TokenStream, + stack: &mut Vec, + ) -> TokenTree { + use syntax::parse::token::*; + + let (tree, is_joint) = stream.as_tree(); + let (span, token) = match tree { + tokenstream::TokenTree::Token(span, token) => (span, token), + tokenstream::TokenTree::Delimited(span, delimed) => { + let delimiter = Delimiter::from_internal(delimed.delim); + let mut g = Group::new(delimiter, ::TokenStream(delimed.tts.into())); + g.set_span(Span(span)); + return g.into(); + } + }; + + let op_kind = if is_joint { + Spacing::Joint + } else { + Spacing::Alone + }; + macro_rules! tt { + ($e:expr) => {{ + let mut x = TokenTree::from($e); + x.set_span(Span(span)); + x + }}; + } + macro_rules! op { + ($a:expr) => { + tt!(Punct::new($a, op_kind)) + }; + ($a:expr, $b:expr) => {{ + stack.push(tt!(Punct::new($b, op_kind))); + tt!(Punct::new($a, Spacing::Joint)) + }}; + ($a:expr, $b:expr, $c:expr) => {{ + stack.push(tt!(Punct::new($c, op_kind))); + stack.push(tt!(Punct::new($b, Spacing::Joint))); + tt!(Punct::new($a, Spacing::Joint)) + }}; + } + + match token { + Eq => op!('='), + Lt => op!('<'), + Le => op!('<', '='), + EqEq => op!('=', '='), + Ne => op!('!', '='), + Ge => op!('>', '='), + Gt => op!('>'), + AndAnd => op!('&', '&'), + OrOr => op!('|', '|'), + Not => op!('!'), + Tilde => op!('~'), + BinOp(Plus) => op!('+'), + BinOp(Minus) => op!('-'), + BinOp(Star) => op!('*'), + BinOp(Slash) => op!('/'), + BinOp(Percent) => op!('%'), + BinOp(Caret) => op!('^'), + BinOp(And) => op!('&'), + BinOp(Or) => op!('|'), + BinOp(Shl) => op!('<', '<'), + BinOp(Shr) => op!('>', '>'), + BinOpEq(Plus) => op!('+', '='), + BinOpEq(Minus) => op!('-', '='), + BinOpEq(Star) => op!('*', '='), + BinOpEq(Slash) => op!('/', '='), + BinOpEq(Percent) => op!('%', '='), + BinOpEq(Caret) => op!('^', '='), + BinOpEq(And) => op!('&', '='), + BinOpEq(Or) => op!('|', '='), + BinOpEq(Shl) => op!('<', '<', '='), + BinOpEq(Shr) => op!('>', '>', '='), + At => op!('@'), + Dot => op!('.'), + DotDot => op!('.', '.'), + DotDotDot => op!('.', '.', '.'), + DotDotEq => op!('.', '.', '='), + Comma => op!(','), + Semi => op!(';'), + Colon => op!(':'), + ModSep => op!(':', ':'), + RArrow => op!('-', '>'), + LArrow => op!('<', '-'), + FatArrow => op!('=', '>'), + Pound => op!('#'), + Dollar => op!('$'), + Question => op!('?'), + SingleQuote => op!('\''), + + Ident(ident, false) => tt!(self::Ident::new(&ident.as_str(), Span(span))), + Ident(ident, true) => tt!(self::Ident::new_raw(&ident.as_str(), Span(span))), + Lifetime(ident) => { + let ident = ident.without_first_quote(); + stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span)))); + tt!(Punct::new('\'', Spacing::Joint)) + } + Literal(lit, suffix) => tt!(self::Literal { + lit, + suffix, + span: Span(span) + }), + DocComment(c) => { + let style = comments::doc_comment_style(&c.as_str()); + let stripped = comments::strip_doc_comment_decoration(&c.as_str()); + let stream = vec![ + tt!(self::Ident::new("doc", Span(span))), + tt!(Punct::new('=', Spacing::Alone)), + tt!(self::Literal::string(&stripped)), + ].into_iter() + .collect(); + stack.push(tt!(Group::new(Delimiter::Bracket, stream))); + if style == ast::AttrStyle::Inner { + stack.push(tt!(Punct::new('!', Spacing::Alone))); + } + tt!(Punct::new('#', Spacing::Alone)) + } + + Interpolated(_) => __internal::with_sess(|sess, _| { + let tts = token.interpolated_to_tokenstream(sess, span); + tt!(Group::new(Delimiter::None, ::TokenStream(tts))) + }), + + DotEq => op!('.', '='), + OpenDelim(..) | CloseDelim(..) => unreachable!(), + Whitespace | Comment | Shebang(..) | Eof => unreachable!(), + } + } + + pub(crate) fn to_internal(self) -> tokenstream::TokenStream { + use syntax::parse::token::*; + use syntax::tokenstream::{Delimited, TokenTree}; + + let (ch, kind, span) = match self { + self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()), + self::TokenTree::Group(tt) => { + return TokenTree::Delimited( + tt.span.0, + Delimited { + delim: tt.delimiter.to_internal(), + tts: tt.stream.0.into(), + }, + ).into(); + } + self::TokenTree::Ident(tt) => { + let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw); + return TokenTree::Token(tt.span.0, token).into(); + } + self::TokenTree::Literal(self::Literal { + lit: Lit::Integer(ref a), + suffix, + span, + }) + if a.as_str().starts_with("-") => + { + let minus = BinOp(BinOpToken::Minus); + let integer = Symbol::intern(&a.as_str()[1..]); + let integer = Literal(Lit::Integer(integer), suffix); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, integer); + return vec![a, b].into_iter().collect(); + } + self::TokenTree::Literal(self::Literal { + lit: Lit::Float(ref a), + suffix, + span, + }) + if a.as_str().starts_with("-") => + { + let minus = BinOp(BinOpToken::Minus); + let float = Symbol::intern(&a.as_str()[1..]); + let float = Literal(Lit::Float(float), suffix); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, float); + return vec![a, b].into_iter().collect(); + } + self::TokenTree::Literal(tt) => { + let token = Literal(tt.lit, tt.suffix); + return TokenTree::Token(tt.span.0, token).into(); + } + }; + + let token = match ch { + '=' => Eq, + '<' => Lt, + '>' => Gt, + '!' => Not, + '~' => Tilde, + '+' => BinOp(Plus), + '-' => BinOp(Minus), + '*' => BinOp(Star), + '/' => BinOp(Slash), + '%' => BinOp(Percent), + '^' => BinOp(Caret), + '&' => BinOp(And), + '|' => BinOp(Or), + '@' => At, + '.' => Dot, + ',' => Comma, + ';' => Semi, + ':' => Colon, + '#' => Pound, + '$' => Dollar, + '?' => Question, + '\'' => SingleQuote, + _ => unreachable!(), + }; + + let tree = TokenTree::Token(span.0, token); + match kind { + Spacing::Alone => tree.into(), + Spacing::Joint => tree.joint(), + } + } +} + +impl Level { + pub(crate) fn to_internal(self) -> errors::Level { + match self { + Level::Error => errors::Level::Error, + Level::Warning => errors::Level::Warning, + Level::Note => errors::Level::Note, + Level::Help => errors::Level::Help, + Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive"), + } + } +} diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index bf790e6143a9..9748e2947eeb 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1775,12 +1775,6 @@ fn ident_continue(c: Option) -> bool { (c > '\x7f' && c.is_xid_continue()) } -// The string is a valid identifier or a lifetime identifier. -pub fn is_valid_ident(s: &str) -> bool { - let mut chars = s.chars(); - ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch))) -} - #[cfg(test)] mod tests { use super::*; From 99eac011c6059de129de4b1c8ab7c6cd6794e6e4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 20 Jul 2018 00:09:05 +0300 Subject: [PATCH 6/6] proc_macro: avoid exposing internal details in formatting impls. --- src/libproc_macro/lib.rs | 44 +++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f63e3e0e4a6f..61da9db76f6c 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -588,7 +588,7 @@ impl fmt::Display for TokenTree { /// A delimited token stream. /// /// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone, Debug)] +#[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Group { delimiter: Delimiter, @@ -682,12 +682,23 @@ impl fmt::Display for Group { } } +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Group { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Group") + .field("delimiter", &self.delimiter()) + .field("stream", &self.stream()) + .field("span", &self.span()) + .finish() + } +} + /// An `Punct` is an single punctuation character like `+`, `-` or `#`. /// /// Multicharacter operators like `+=` are represented as two instances of `Punct` with different /// forms of `Spacing` returned. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Punct { ch: char, spacing: Spacing, @@ -771,8 +782,19 @@ impl fmt::Display for Punct { } } +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Punct") + .field("ch", &self.as_char()) + .field("spacing", &self.spacing()) + .field("span", &self.span()) + .finish() + } +} + /// An identifier (`ident`). -#[derive(Clone, Debug)] +#[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Ident { sym: Symbol, @@ -851,10 +873,17 @@ impl Ident { #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.is_raw { - f.write_str("r#")?; - } - self.sym.as_str().fmt(f) + TokenStream::from(TokenTree::from(self.clone())).fmt(f) + } +} + +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Ident") + .field("ident", &self.to_string()) + .field("span", &self.span()) + .finish() } } @@ -862,6 +891,7 @@ impl fmt::Display for Ident { /// character (`'a'`), byte character (`b'a'`), an integer or floating point number /// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). /// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. +// FIXME(eddyb) `Literal` should not expose internal `Debug` impls. #[derive(Clone, Debug)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Literal {