Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macros: limitation in the expression parser for <$:path>::<ident> #48067

Open
behnam opened this issue Feb 8, 2018 · 8 comments
Open

Macros: limitation in the expression parser for <$:path>::<ident> #48067

behnam opened this issue Feb 8, 2018 · 8 comments
Assignees
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The parsing of Rust source code to an AST C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@behnam
Copy link
Contributor

behnam commented Feb 8, 2018

Background: https://users.rust-lang.org/t/macros-using-path-tokens-with-format-args/15480

When passing in a path token to a macro, then trying to suffix the metavariable with ::<ident> (or more), the parser cannot recognize the whole thing as an :expr, which causes failures on calls to macros like format_args!.

Repro:

macro_rules! something {
    ( $path:path ) => (
        //println!("Say: {}", $path::say);
        format_args!("Say: {}", $path::say);
    );
}

mod foo {
    const say: &str = "Hello";
}

mod bar {
    const say: &str = "World";

    mod baz {
        const say: &str = "Universe";
    }
}

fn main() {
    something!(foo);
    something!(bar);
    something!(bar::baz);
}

It fails with three instances of this error (with RUSTFLAGS='-Z external-macro-backtrace'):

error: expected token: `,`
  --> src/main.rs:4:9
   |
1  | / macro_rules! talk {
2  | |     ( $mod:path ) => (
3  | |         // print!("Say: {}", $mod::say);
4  | |         format_args!("Say: {}", $mod::say);
   | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5  | |     );
6  | | }
   | |_- in this expansion of `talk!`
...
21 |       talk!(foo);
   |       ----------- in this macro invocation

A workaround is to use:

{ use $path as base; base::say }

but would be great if we could just use:

$path::say

I couldn't find an existing report. I'm guessing it falls under RFE.

@behnam behnam changed the title Macros: limitation in the expression parser for <$:path>::<tt> Macros: limitation in the expression parser for <$:path>::<ident> Feb 8, 2018
@durka
Copy link
Contributor

durka commented Feb 9, 2018

cc @jseyfried

This is known issue, but I don't know how hard it would be to make it "just work".

@petrochenkov
Copy link
Contributor

We can even do $path1::$path2 in general, this is very similar to what nested groups in imports already have to deal with.
I'll assign to myself, because this is already in my queue.

@petrochenkov petrochenkov self-assigned this Feb 9, 2018
@pietroalbini pietroalbini added C-enhancement Category: An issue proposing an enhancement or a PR with one. A-parser Area: The parsing of Rust source code to an AST A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 10, 2018
@reuvenpo
Copy link

I just ran into this myself.
has there been any progress on this since 2018?

@petrochenkov
Copy link
Contributor

No progress, someone needs to try implementing this and make a PR.
The relevant code is in librustc_parse in fn parse_path.

@reuvenpo
Copy link

I see.. thanks for the quick response!
Unfortunately I don't have the time or expertise with the rustc parser to do it myself...

@fanzeyi
Copy link

fanzeyi commented Feb 6, 2021

I just run into a variation of this issue today. I was trying to append another $path to a path metavariable argument, and the parser is unwilling to treat the result as path. The use as trick in the original discussion solves it. Small example:

struct Foo;

macro_rules! test {
    (inner, $tr: path) => {
        impl $tr for Foo {}
    };
    ($cr: path) => { test!(inner, $cr::Buf); }
}

test!(bytes);

This generates an error: no rules expected the token `::` . Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=da96a1f6c5560762d2374465dda9888f

@Wandalen
Copy link

Wandalen commented May 5, 2022

Me too encounter the problem. As workaround I used pattern $Va : ident $( :: $Vb : ident )* instead of path.

@DylanRJohnston-FZ
Copy link

@Wandalen life saver!. I ran into this issue trying to write a macro that adds to_owned() to every field of a struct.

macro_rules! all_owned {
    ($first:ident$(::$rest:ident)* { $($key:ident:$value:expr,)* })  => {
        $first$(::$rest)* {
            $($key: ($value).to_owned(),)*
        }
    };
}

badicsalex added a commit to badicsalex/hun_law_rs that referenced this issue Jul 12, 2022
For some reason $path::whatever is not a valid `path` according to rustc.

See:
- nextest-rs/datatest-stable#4
- rust-lang/rust#48067
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The parsing of Rust source code to an AST C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants