Fix the grammar of function pointer types#2240
Fix the grammar of function pointer types#2240fmease wants to merge 4 commits intorust-lang:masterfrom
Conversation
* `safe` is a syntactically valid function pointer type qualifier next to `unsafe` but it wasn't listed prior. * renamed `ItemSafety` to `Safety` since it's now also used in the grammar of function pointer types * footnote on non-terminal `Safety` in rule `StaticItem` called `safe` & `unsafe` *function* modifiers when they're evidentally more general and can be placed on *static* items * made the footnotes related to `Safety` more precise
The grammar was incorrect since * C variadics `...` no longer need to be preceded by a normal parameter * that's the case since <rust-lang/rust#124048> * C variadics don't need to be the final element, `fn(..., i32)` is perfectly fine * C variadics can indeed be named (e.g., `fn f(_: ...)` or `fn(v: ...)`) * C variadics can be followed by a comma (e.g., `fn(...,)`)
`fn(&self)`, `fn(&'static mut self)` etc. are syntactically valid function pointer types
It's not just (common) identifiers or underscores, it's more complex.
| MaybeNamedFunctionParametersVariadic -> | ||
| ( MaybeNamedParam `,` )* MaybeNamedParam `,` OuterAttribute* `...` | ||
| MaybeNamedPattern -> | ||
| `mut`? IDENTIFIER | ( `&` | `&&` )? ( `_` | `false` | `true` ) |
There was a problem hiding this comment.
Yes, indeed, that's the grammar! It's a tiny subset of patterns.
Note that this subgrammar is also used for associated functions in traits in Rust 2015. I didn't know how I am meant to branch on editions, so I didn't update the corresponding function item grammar that currently only has FunctionParam -> … Type[^fn-param-2015] … which is not sufficient strictly speaking.
I guess I could do sth. akin to "ModernGrammar[^1] | LegacyGrammar[^2] // [^1]: Rust 2018–2024 // [^2]: Rust 2015 only" (pseudo). Let me know what you think.
|
r? ehuss or reassign |
|
|
||
| [^fn-param-2015]: Function parameters with only a type are only allowed in an associated function of a [trait item] in the 2015 edition. | ||
|
|
||
| [^safe-semantics]: The `safe` qualifier is only allowed semantically on functions and function pointer types within `extern` blocks. |
There was a problem hiding this comment.
| [^safe-semantics]: The `safe` qualifier is only allowed semantically on functions and function pointer types within `extern` blocks. | |
| [^safe-semantics]: The `safe` qualifier is only allowed semantically on functions within `extern` blocks. |
oops
| MaybeNamedFunctionParametersVariadic -> | ||
| ( MaybeNamedParam `,` )* MaybeNamedParam `,` OuterAttribute* `...` | ||
| MaybeNamedPattern -> | ||
| `mut`? IDENTIFIER | ( `&` | `&&` )? ( `_` | `false` | `true` ) |
There was a problem hiding this comment.
TODO: Note somewhere (maybe in a footnote that semantically only identifiers and underscores are valid)
There was a problem hiding this comment.
Thanks!
This is just an initial review. I think we'll want to add rules that express each of the semantic restrictions. Whether it's conditional (like items.fn.safety-qualifiers) or unconditional (like items.traits.associated-visibility).
| MaybeNamedFunctionParametersVariadic -> | ||
| ( MaybeNamedParam `,` )* MaybeNamedParam `,` OuterAttribute* `...` | ||
| MaybeNamedPattern -> | ||
| `mut`? IDENTIFIER | ( `&` | `&&` )? ( `_` | `false` | `true` ) |
There was a problem hiding this comment.
This doesn't look quite right. My understanding is that this logic comes from is_named_param.
I think it would look something closer to:
| `mut`? IDENTIFIER | ( `&` | `&&` )? ( `_` | `false` | `true` ) | |
| ((`mut`? | `&` | `&&`)? IDENTIFIER) | ((`&` | `&&`)? (`_` | `false` | `true`)) |
because ident can be preceded by & or &&.
However, this seems to be getting close to the territory of unintentional behavior. I'm wondering if this really is a bug in the compiler, and the grammar should be something else.
|
I did some research to see how these got missed. Some of them just weren't communicated during implementation/stabilization. Some were just missed when reverse-engineering the compiler. Some were missed when trying to handle too many things at once.
trailing
function pointer parameters have limited patterns -- Missed in initial introduction in #433. I don't remember what happened there. The current behavior does not look intentional to me, though. |
The grammar of function pointer types on master drastically diverges from reality.
Please read the individual commit messages for details (changes, motivation).
For example, according to the grammar on master, the following snippets are syntactically illegal but that is in conflict with rustc which deems them syntactically well-formed:
safe fn()fn(...),fn(...,),fn(_: ...),fn(v: ...),fn(..., ())fn(&self),fn(&'static mut self, ())fn(mut x: ()),fn(false: bool),fn(&_: ()),fn(&&true: ())Context: #t-lang > Naming arguments in Fn traits and rust-lang/rfcs#3955 where this was quite relevant.