Skip to content

None-delimited identifiers (sometimes) stringified with strange spaces #55658

Closed
@dtolnay

Description

@dtolnay

I have the following procedural macro and invocation of the macro. In this code I construct two identical functions f and g which simply return stringify!(i32), but with a none-delimited group around the i32 (because of #55557). As far as I can tell the function bodies of f and g are identical token streams.

But f returns "i32" and g returns " i32 ".

I believe that as written, both functions should return "i32" without spaces.

extern crate proc_macro;
use self::proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};

use std::iter::FromIterator;

#[proc_macro]
pub fn repro(input: TokenStream) -> TokenStream {
    println!("{:#?}", input);

    TokenStream::from_iter(vec![
        // fn f() -> &'static str { $input }
        TokenTree::Ident(Ident::new("fn", Span::call_site())),
        TokenTree::Ident(Ident::new("f", Span::call_site())),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
        TokenTree::Punct(Punct::new('-', Spacing::Joint)),
        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
        TokenTree::Punct(Punct::new('&', Spacing::Alone)),
        TokenTree::Punct(Punct::new('\'', Spacing::Joint)),
        TokenTree::Ident(Ident::new("static", Span::call_site())),
        TokenTree::Ident(Ident::new("str", Span::call_site())),
        TokenTree::Group(Group::new(Delimiter::Brace, input)),

        // fn g() -> &'static str { stringify!(i32) }
        TokenTree::Ident(Ident::new("fn", Span::call_site())),
        TokenTree::Ident(Ident::new("g", Span::call_site())),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
        TokenTree::Punct(Punct::new('-', Spacing::Joint)),
        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
        TokenTree::Punct(Punct::new('&', Spacing::Alone)),
        TokenTree::Punct(Punct::new('\'', Spacing::Joint)),
        TokenTree::Ident(Ident::new("static", Span::call_site())),
        TokenTree::Ident(Ident::new("str", Span::call_site())),
        TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("stringify", Span::call_site())),
            TokenTree::Punct(Punct::new('!', Spacing::Alone)),
            TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::from_iter(vec![
                TokenTree::Group(Group::new(Delimiter::None, TokenStream::from_iter(vec![
                    TokenTree::Ident(Ident::new("i32", Span::call_site())),
                ]))),
            ]))),
        ])))
    ])
}
macro_rules! m {
    ($id:ident) => {
        repro::repro! {
            stringify!($id)
        }
    }
}

m!(i32);

fn main() {
    assert_eq!(f(), "i32", "f()");
    assert_eq!(g(), "i32", "g()"); // broken, is `"  i32  "`
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)C-bugCategory: This is a bug.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions