1
Fork 0

Rollup merge of #78376 - Aaron1011:feature/consistent-empty-expr, r=petrochenkov

Treat trailing semicolon as a statement in macro call

See #61733 (comment)

We now preserve the trailing semicolon in a macro invocation, even if
the macro expands to nothing. As a result, the following code no longer
compiles:

```rust
macro_rules! empty {
    () => { }
}

fn foo() -> bool { //~ ERROR mismatched
    { true } //~ ERROR mismatched
    empty!();
}
```

Previously, `{ true }` would be considered the trailing expression, even
though there's a semicolon in `empty!();`

This makes macro expansion more token-based.
This commit is contained in:
Yuki Okushi 2020-11-03 15:27:03 +09:00 committed by GitHub
commit 0716724a0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 2 deletions

View file

@ -310,8 +310,44 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
};
if style == ast::MacStmtStyle::Semicolon {
// Implement the proposal described in
// https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449
//
// The macro invocation expands to the list of statements.
// If the list of statements is empty, then 'parse'
// the trailing semicolon on the original invocation
// as an empty statement. That is:
//
// `empty();` is parsed as a single `StmtKind::Empty`
//
// If the list of statements is non-empty, see if the
// final statement alreayd has a trailing semicolon.
//
// If it doesn't have a semicolon, then 'parse' the trailing semicolon
// from the invocation as part of the final statement,
// using `stmt.add_trailing_semicolon()`
//
// If it does have a semicolon, then 'parse' the trailing semicolon
// from the invocation as a new StmtKind::Empty
// FIXME: We will need to preserve the original
// semicolon token and span as part of #15701
let empty_stmt = ast::Stmt {
id: ast::DUMMY_NODE_ID,
kind: ast::StmtKind::Empty,
span: DUMMY_SP,
tokens: None,
};
if let Some(stmt) = stmts.pop() {
stmts.push(stmt.add_trailing_semicolon());
if stmt.has_trailing_semicolon() {
stmts.push(stmt);
stmts.push(empty_stmt);
} else {
stmts.push(stmt.add_trailing_semicolon());
}
} else {
stmts.push(empty_stmt);
}
}