}
impl Stmt {
+ pub fn has_trailing_semicolon(&self) -> bool {
+ match &self.kind {
+ StmtKind::Semi(_) => true,
+ StmtKind::MacCall(mac) => matches!(mac.style, MacStmtStyle::Semicolon),
+ _ => false,
+ }
+ }
pub fn add_trailing_semicolon(mut self) -> Self {
self.kind = match self.kind {
StmtKind::Expr(expr) => StmtKind::Semi(expr),
};
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);
}
}
fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
if let Some((span, multiple)) = seq.take() {
+ // FIXME: Find a better way of ignoring the trailing
+ // semicolon from macro expansion
+ if span == rustc_span::DUMMY_SP {
+ return;
+ }
cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
let (msg, rem) = if multiple {
("unnecessary trailing semicolons", "remove these semicolons")
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/empty-trailing-stmt.rs:6:7
+ |
+LL | { true }
+ | ^^^^ expected `()`, found `bool`
+
+error[E0308]: mismatched types
+ --> $DIR/empty-trailing-stmt.rs:5:13
+ |
+LL | fn foo() -> bool {
+ | --- ^^^^ expected `bool`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.