Skip to content

Always parse macro invocations with () or [] as expressions #378

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions text/0000-expr-macros.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
- Start Date: 2014-10-09
- RFC PR #: (leave this empty)
- Rust Issue #: (leave this empty)

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` don’t 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 aren’t being used as
expressions. This would have the downside of requiring semicolons after every
`macro_rules!` declaration.

Unresolved questions
====================

None.