From bd10ffa38416864868fbe636d5a1bb4f77ae8dec Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 1 Jun 2020 05:34:29 -0400 Subject: [PATCH] Handle `Group`s with `Delimiter::None` (#50) Currently, rustc does not pass the exact original `TokenStream` to proc-macros in several cases. This has many undesirable effects, such as losing correct location information in error message. See https://github.com/rust-lang/rust/issues/43081 for more details In the future, rustc will begin passing the correct `TokenStream` to proc-macros. As a result, some tokens may be wrapped in a `TokenTree::Group` with `Delimiter::None` (when the tokens originally came from a `macro_rules!`) macro expansion. I've determined that this change will cause your crate to stop working on some inputs. This PR updates `hex-literal-impl` to be compatible with both the old and new `TokenStream` contents. If you have any questions, feel free to ask me. See https://github.com/rust-lang/rust/issues/72622 for more details --- hex-literal/hex-literal-impl/src/lib.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/hex-literal/hex-literal-impl/src/lib.rs b/hex-literal/hex-literal-impl/src/lib.rs index dfa34084..bc4e6151 100644 --- a/hex-literal/hex-literal-impl/src/lib.rs +++ b/hex-literal/hex-literal-impl/src/lib.rs @@ -1,6 +1,6 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenTree}; +use proc_macro::{TokenStream, TokenTree, Delimiter}; use proc_macro_hack::proc_macro_hack; fn is_hex_char(c: &char) -> bool { @@ -17,8 +17,29 @@ fn is_format_char(c: &char) -> bool { } } + +/// Strips any outer `Delimiter::None` groups from the input, +/// returning a `TokenStream` consisting of the innermost +/// non-empty-group `TokenTree`. +/// This is used to handle a proc macro being invoked +/// by a `macro_rules!` expansion. +/// See https://github.com/rust-lang/rust/issues/72545 for background +fn ignore_groups(mut input: TokenStream) -> TokenStream { + let mut tokens = input.clone().into_iter(); + loop { + if let Some(TokenTree::Group(group)) = tokens.next() { + if group.delimiter() == Delimiter::None { + input = group.stream(); + continue; + } + } + return input; + } +} + #[proc_macro_hack] -pub fn hex(input: TokenStream) -> TokenStream { +pub fn hex(mut input: TokenStream) -> TokenStream { + input = ignore_groups(input); let mut ts = input.into_iter(); let input = match (ts.next(), ts.next()) { (Some(TokenTree::Literal(literal)), None) => literal.to_string(),