Skip to content

In macros, $($x:expr),* fragments can be used to bypass future-proofing restrictions #25658

Closed

Description

@nikomatsakis

This should not be accepted, but it is:

macro_rules! foo {
    ( $($x:expr),* ... ) => { 1 }
}

fn main() { }

cc @pnkfelix @cmr

Activity

  1. nikomatsakis commented on May 20, 2015

    @nikomatsakis
    ContributorAuthor
  2. nikomatsakis commented on May 20, 2015

    @nikomatsakis
    ContributorAuthor

    Note that

    macro_rules! foo {
        ( $x:expr ... ) => { 1 }
    }
    
    fn main() { }

    is (correctly) prohibited.

  3. bluss commented on May 20, 2015

    @bluss
    Contributor

    It's not just the type expr, I also tested pat.

  4. DanielKeep commented on May 21, 2015

    @DanielKeep
    Contributor

    Nooooooo! You're going to break my macro article again, aren't you? :(

    (Note: I realise the following is not a good reason to not fix this problem.)

    The problem for me, personally, is that the following doesn't work:

    macro_rules! foo {
        ( $($x:expr),* , ... ) => { 1 }
    }
    
    fn main() {
    // error: local ambiguity: multiple parsing options: built-in NTs expr ('x') or 1 other options.
        let _ = foo!(1, 2, 3, ...);
    //                        ^~~
    }

    It would be nice if MBE preferred literal matches to captures.

  5. Stebalien commented on May 21, 2015

    @Stebalien
    Contributor

    @DanielKeep Shouldn't that be $($x:expr,)*? Your example won't work anyways for the reason you posted but fixing this bug shouldn't change anything. Anyways, you should be able to do this with a recursive macro:

    macro_rules! foo {
        (...) => {{
            ()
        }};
        ($e:expr, $($tok:tt)+) => {{
            ($e, foo!($($tok)+))
        }}
    }
    
    fn main() {
        let tpl = foo!(1,2,3,4,...);
        println!("{:?}", tpl);
    }
  6. added
    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
    on May 21, 2015
  7. alexcrichton commented on May 26, 2015

    @alexcrichton
    Member

    triage: I-nominated

  8. nikomatsakis commented on Jun 2, 2015

    @nikomatsakis
    ContributorAuthor
  9. nikomatsakis commented on Jun 2, 2015

    @nikomatsakis
    ContributorAuthor

    So my feeling is that we should probably fix this, but it'd be good to evaluate the impact. It might be a good place to use a more elongated "breaking change procedure", or at least actively reach out to help people rewrite.

  10. emberian commented on Jun 2, 2015

    @emberian
    Contributor

    Is this a bug where we need to consider "FOLLOW"? I thought I saw a PR/RFC that added detailed FOLLOW checking but I could be wrong.

  11. bluss commented on Jun 2, 2015

    @bluss
    Contributor

    Would it be a middle ground to always warn on this, and then "just let it break" if expression syntax ever changes so that it does -- the macro would suddenly match differently.

    @DanielKeep and I found out a parsing strategy with $x:tt $($xs:tt)* where you can split on any token you want to and reinterpret the parts on either side. That is like an explicit way to circumvent any syntax restriction, and it's not tied to any changing meaning of expr or similar macro parts.

  12. nikomatsakis commented on Jun 3, 2015

    @nikomatsakis
    ContributorAuthor

    triage: P-high

    Assigning high priority as, if we are going to fix this, we need to do it soon. If we're just going to warn, urgency is somewhat lower. I'm not yet sure of best overall strategy here. A crater report might be helpful in making the determination.

  13. 11 remaining items

  14. nikomatsakis commented on Nov 17, 2015

    @nikomatsakis
    ContributorAuthor

    OK, so, this "trailing comma" pattern jumps out: $($vs:expr),* $(,)*, and it seems like this IS a case where a knowledge of FIRST would solve the issue, right? (depending, I guess, on what comes after the $(,)*...?)

  15. pnkfelix commented on Nov 18, 2015

    @pnkfelix
    Contributor

    this "trailing comma" pattern jumps out: $($vs:expr),* $(,)*, and it seems like this IS a case where a knowledge of FIRST would solve the issue, right?

    @nikomatsakis yes I think that is right. I'm working on a revised version of the code that does a more precise computation of FIRST for the suffix after the cursor (and also tracks LAST for the token sequence prefix before the cursor, since you can have things like $($a:expr $( stuff; )*) $(,)*), and so when the cursor is right before the $(,)*, the LAST would hold { expr, ';' } The current code doesn't appear to be general enough to possibly be handling that correctly.

  16. pnkfelix commented on Nov 18, 2015

    @pnkfelix
    Contributor

    results of new crater run with a smarter (still in development) changeset:

    https://gist.github.com/pnkfelix/b351caa523d45f9aa86b

    I interpret this as a signal that I need to add { to the follow set for expr and probably all other NT's. But the other non-noise regressions there look legit:

    • expr followed by ...
    • ty followed by functions
    • ty followed by |
    • ty followed by varargs
    • expr followed by _
    • ty followed by [
    • expr followed by copy
    • expr followed by swap
    • ty followed by where (actually, we can/should expand the follow set of ty to include where).

    (Some of the regressing crates fall into more than one of the buckets above...)

  17. durka commented on Nov 24, 2015

    @durka
    Contributor

    I don't understand disallowing ty |, to be honest. Clearly a type can be followed by | since that is the syntax of closures.

  18. durka commented on Nov 24, 2015

    @durka
    Contributor

    Also, as a matter of policy, could/should crate authors be notified (assuming an email was provided) when their crate is caught regressing in a crater run related to an accepted breaking change?

  19. huonw commented on Nov 24, 2015

    @huonw
    Contributor

    I don't understand disallowing ty |, to be honest. Clearly a type can be followed by | since that is the syntax of closures.

    Almost certainly an oversight. Good point!

  20. nikomatsakis commented on Dec 1, 2015

    @nikomatsakis
    ContributorAuthor

    On Wed, Nov 18, 2015 at 08:53:16AM -0800, Felix S Klock II wrote:

    results of new crater run with a smarter (still in development) changeset:

    https://gist.github.com/pnkfelix/b351caa523d45f9aa86b

    I interpret this as a signal that I need to add { to the follow set for expr and probably all other NT's.

    I still feel uncomfortable with this. I would rather than a nt for
    "expr that cannot have {", which would correspond to basically "the
    stuff you can put in an if". I realize this is not backwards compat
    though, but it seems like having { in follow set of expr is
    just...bogus. (e.g. imagine we make break take an argument.)

    Perhaps though there is a compromise:

    • add another fragment specifier for expr-minus-{
    • add a lint warning that suggests people change expr to expr-minus-{ when
      appropriate
  21. pnkfelix commented on Dec 2, 2015

    @pnkfelix
    Contributor

    @nikomatsakis

    Perhaps though there is a compromise:

    • add another fragment specifier for expr-minus-{
    • add a lint warning that suggests people change expr to expr-minus-{ when appropriate

    yeah, I have come around to seeing this as a better solution (see e.g. rust-lang/rfcs#1384 (comment) )

    Just need to think of a good name for the specifier. :)

  22. pnkfelix commented on Dec 17, 2015

    @pnkfelix
    Contributor

    now that amendment rust-lang/rfcs#1384 has been accepted, this issue should be fixed once the implementation has landed (i.e. #30450 is resolved).

  23. retep998 commented on Jan 13, 2016

    @retep998
    Contributor

    I should point out that crater is still massively deficient as it still does not test Windows targets at all, and did not notice that winapi would be hit by the ty followed by [ change. Even if I fix this on my end, it will still end up breaking everyone on windows who uses an older version of winapi. Please reconsider at least this case.

    C:\msys64\home\Peter\.cargo\registry\src\github.life-white.uk-88ac128001ac3a9a\winapi-0.2.5\src\macros.rs:159:46: 159:47 warning: `$fieldtype:ty` is followed by `[`, which is not allowed for `ty` fragments
    C:\msys64\home\Peter\.cargo\registry\src\github.life-white.uk-88ac128001ac3a9a\winapi-0.2.5\src\macros.rs:159     ($base:ident $field:ident: $fieldtype:ty [
                                                                                                                                                     ^
    C:\msys64\home\Peter\.cargo\registry\src\github.life-white.uk-88ac128001ac3a9a\winapi-0.2.5\src\macros.rs:159:46: 159:47 note: The above warning will be a hard error in the next release.
    C:\msys64\home\Peter\.cargo\registry\src\github.life-white.uk-88ac128001ac3a9a\winapi-0.2.5\src\macros.rs:159     ($base:ident $field:ident: $fieldtype:ty [
                                                                                                                                                     ^
    
  24. pnkfelix commented on Jan 14, 2016

    @pnkfelix
    Contributor

    Cc @brson re above crater note

    (I strongly doubt we would revert the RFC amendment or associated PR. you might find support for adding [ to FOLLOW of ty )

  25. nikomatsakis commented on Jan 14, 2016

    @nikomatsakis
    ContributorAuthor

    @retep998 Thanks for bringing this up. I assure you the deficiencies of crater are well-known, and it'd be really great if we could improve it -- though even if we got 100% coverage for crates.io, obviously it still wouldn't be 100% coverage of all the Rust code out there. In any case though, this is part of why we try our best to do warning cycles for bug fixes that are likely to have major impact, so that we can find out about other problems before changes become permanent (and also of course to give people time to transition).

    As @pnkfelix said, I don't think it makes sense to rollback this bug fix completely or anything like that. It might alleviate some short term pain but it'd be guaranteed to cause more breakage in the long-term, since basically every change to Rust's grammar would be a potential breaking change to some macro.

    However, also as @pnkfelix said, adding [ to the follow set is a plausible change. I don't think I'd have added it initially, as it is not something that follows from today's grammar (I don't think). It'd be a restriction on future types, but I tend to think since we have [T], I'd be disinclined to add T[...] anyway, since it seems ripe for confusion. Worth strong consideration, certainly.

  26. pnkfelix commented on Jan 14, 2016

    @pnkfelix
    Contributor

    This issue (as described in the description) is fixed by #30694

  27. added a commit that references this issue on Jun 8, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)P-highHigh priorityT-langRelevant to the language team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions