Skip to content

Generic/where clause bounds generated by a macro fail to parse even when syntactically correct #38461

@abonander

Description

@abonander

There is no fragment specifier to make $genericbnd work in the following macro:

(playpen)

macro_rules! takes_fn {
    (fn $fnname:ident <$generic:ident : $genericbnd:ty> () {}) => (
        fn $fnname <$generic : $genericbnd > () {}
    )
}

takes_fn! {
    fn foo<T: ToString>() {}
}

The parser assumes the $generic token encompasses the whole type and fails to parse the actual bound:

error: expected one of `,`, `=`, `>`, or `?`, found `ToString`
 --> <anon>:3:32
  |
3 |         fn $fnname <$generic : $genericbnd > () {}
  |                                ^^^^^^^^^^^

This similarly fails with where clauses:

(playpen)

macro_rules! takes_fn {
    (fn $fnname:ident <$generic:ident> () where $whereid:path : $wherebnd:ty {}) => (
        fn $fnname <$generic> () where $whereid : $wherebnd {}
    )
}

takes_fn! {
    fn foo<T>() where T: ToString {}
}

Which yields the following error:

error: each predicate in a `where` clause must have at least one bound in it
 --> <anon>:3:40
  |
3 |         fn $fnname <$generic> () where $whereid : $wherebnd {}
  |                                        ^^^^^^^^^^

error: expected one of `,`, `?`, or `{`, found `ToString`
 --> <anon>:3:51
  |
3 |         fn $fnname <$generic> () where $whereid : $wherebnd {}
  |              

This makes it very difficult to create macros which wrap the generation of an item containing generic bounds or where clauses. It would be nice to just use tt for the generics but > is not a valid closing delimiter for stopping a tt fragment at the end of the generics clause, and neither is { for stopping it at the end of a where clause. This can be done if you modify the Rust grammar to wrap generics and where clauses in parenthesis or curly brackets (because tt will not eat a closing parenthesis or curly bracket), but this is ugly and unintuitive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions