Skip to content

macro_rules! thinks use is an ident. It isn't. #40569

Closed

Description

@sgrif

This code should fail to compile, giving the same error message as fn use() would give, but it compiles successfully.

macro_rules! foo {
    ($foo:ident) => {}
}

fn main() {
    foo!(use);
}

This code should compile successfully. However, it fails complaining that it can't decide whether use is an ident or not (hint: it isn't). It also shouldn't be trying to match use as an ident because of the semicolon, but that's a broader/deeper issue with macro_rules!

macro_rules! foo {
    ($(use ;)* $foo:ident) => {}
}

fn main() {
    foo!(use ; use ; bar);
}

Activity

  1. petrochenkov commented on Mar 16, 2017

    @petrochenkov
    Contributor

    ident matcher accepts keywords (and also reserved keywords) by design (see very similar issue about self - #27899 (comment) cc @nrc).

  2. sgrif commented on Mar 16, 2017

    @sgrif
    ContributorAuthor

    From that issue:

    I suppose, ident can be backward compatibly restricted to reject keywords and reserved identifiers with exception of path segment keywords super, self and Self (because you may want to write things like $seg: ident => $seg::foo::bar), but I don't see much benefit from such restriction.

    The second case given in this issue is a very concrete benefit from that restriction. 😄

  3. sgrif commented on Mar 16, 2017

    @sgrif
    ContributorAuthor

    It looks like repeaters can pretty easily confuse macro_rules! even in more ridiculous cases. e.g.

    macro_rules! my_struct {
        ($(#[$meta:meta])* $ident:ident) => {
            $(#[$meta])* struct $ident;
        }
    }
    
    my_struct!(#[derive(Debug)] Foo);

    causes it to complain that it doesn't know if # is supposed to be an ident or not

  4. durka commented on Mar 16, 2017

    @durka
    Contributor

    The repetition thing is because macro_rules just doesn't attempt any backtracking. This has been reported before. You need to put a constant token in between (e.g. struct). It's obviously not backwards compatible to change the definition of ident now, I don't know what @petrochenkov was talking about in that quote...

  5. dtolnay commented on Mar 16, 2017

    @dtolnay
    Member

    One specific common macro that this would break is Serde's forward_to_deserialize_any which accepts "struct" and "enum" as idents.

  6. added
    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
    on Jun 22, 2017
  7. added a commit that references this issue on Jul 11, 2017
  8. petrochenkov commented on Aug 14, 2019

    @petrochenkov
    Contributor

    Closing as works-as-expected and cannot-be-changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions