RFC 378 is to always parse `macro!()`/`macro![]` as expressions

This commit is contained in:
P1start 2014-10-09 16:30:54 +13:00 committed by Felix S. Klock II
parent 9bf2874726
commit 4738e174fc
1 changed files with 75 additions and 0 deletions

75
text/0378-expr-macros.md Normal file
View File

@ -0,0 +1,75 @@
- Start Date: 2014-10-09
- RFC PR #: https://github.com/rust-lang/rfcs/pull/378
- Rust Issue #: https://github.com/rust-lang/rust/issues/18635
Summary
=======
Parse macro invocations with parentheses or square brackets as expressions no
matter the context, and require curly braces or a semicolon following the
invocation to invoke a macro as a statement.
Motivation
==========
Currently, macros that start a statement want to be a whole statement, and so
expressions such as `foo!().bar` dont parse if they start a statement. The
reason for this is because sometimes one wants a macro that expands to an item
or statement (for example, `macro_rules!`), and forcing the user to add a
semicolon to the end is annoying and easy to forget for long, multi-line
statements. However, the vast majority of macro invocations are not intended to
expand to an item or statement, leading to frustrating parser errors.
Unfortunately, this is not as easy to resolve as simply checking for an infix
operator after every statement-like macro invocation, because there exist
operators that are both infix and prefix. For example, consider the following
function:
```rust
fn frob(x: int) -> int {
maybe_return!(x)
// Provide a default value
-1
}
```
Today, this parses successfully. However, if a rule were added to the parser
that any macro invocation followed by an infix operator be parsed as a single
expression, this would still parse successfully, but not in the way expected: it
would be parsed as `(maybe_return!(x)) - 1`. This is an example of how it is
impossible to resolve this ambiguity properly without breaking compatibility.
Detailed design
===============
Treat all macro invocations with parentheses, `()`, or square brackets, `[]`, as
expressions, and never attempt to parse them as statements or items in a block
context unless they are followed directly by a semicolon. Require all
item-position macro invocations to be either invoked with curly braces, `{}`, or
be followed by a semicolon (for consistency).
This distinction between parentheses and curly braces has precedent in Rust:
tuple structs, which use parentheses, must be followed by a semicolon, while
structs with fields do not need to be followed by a semicolon. Many constructs
like `match` and `if`, which use curly braces, also do not require semicolons
when they begin a statement.
Drawbacks
=========
- This introduces a difference between different macro invocation delimiters,
where previously there was no difference.
- This requires the use of semicolons in a few places where it was not necessary
before.
Alternatives
============
- Require semicolons after all macro invocations that arent being used as
expressions. This would have the downside of requiring semicolons after every
`macro_rules!` declaration.
Unresolved questions
====================
None.