From 9e1cf2098d68356bccf7112bbff1d9b565e80a02 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Dec 2023 16:30:34 -0800 Subject: [PATCH] Macro call with braces does not require semicolon to be statement This commit by itself is supposed to have no effect on behavior. All of the call sites are updated to preserve their previous behavior. The behavior changes are in the commits that follow. --- compiler/rustc_ast/src/util/classify.rs | 30 +++++++++++-------- compiler/rustc_ast_pretty/src/pprust/state.rs | 5 +++- .../src/pprust/state/fixup.rs | 6 +++- compiler/rustc_lint/src/unused.rs | 5 +++- compiler/rustc_parse/src/parser/expr.rs | 16 +++++++--- compiler/rustc_parse/src/parser/stmt.rs | 11 +++++-- 6 files changed, 50 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 5ed8d95b12d3..86383af1f7c8 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -42,19 +42,23 @@ use crate::{ast, token::Delimiter}; /// _ => m! {} - 1, // binary subtraction operator /// } /// ``` -#[allow(non_snake_case)] -pub fn expr_requires_semi_to_be_stmt_FIXME(e: &ast::Expr) -> bool { - !matches!( - e.kind, - ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop { .. } - | ast::ExprKind::TryBlock(..) - | ast::ExprKind::ConstBlock(..) - ) +pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { + use ast::ExprKind::*; + + match &e.kind { + If(..) + | Match(..) + | Block(..) + | While(..) + | Loop(..) + | ForLoop { .. } + | TryBlock(..) + | ConstBlock(..) => false, + + MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace, + + _ => true, + } } /// If an expression ends with `}`, returns the innermost expression ending in the `}` diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index be98b7d37d4a..fe17ff41bc34 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1253,7 +1253,10 @@ impl<'a> State<'a> { ast::StmtKind::Expr(expr) => { self.space_if_not_bol(); self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt()); - if classify::expr_requires_semi_to_be_stmt_FIXME(expr) { + if match expr.kind { + ast::ExprKind::MacCall(_) => true, + _ => classify::expr_requires_semi_to_be_stmt(expr), + } { self.word(";"); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs index 363243215a37..9934f972f9bf 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs @@ -128,7 +128,11 @@ impl FixupContext { /// The documentation on `FixupContext::leftmost_subexpression_in_stmt` has /// examples. pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool { - self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt_FIXME(expr) + self.leftmost_subexpression_in_stmt + && match expr.kind { + ExprKind::MacCall(_) => false, + _ => !classify::expr_requires_semi_to_be_stmt(expr), + } } /// Determine whether parentheses are needed around the given `let` diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 7dca70179503..19b71564e2eb 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -688,7 +688,10 @@ trait UnusedDelimLint { ExprKind::Index(base, _subscript, _) => base, _ => break, }; - if !classify::expr_requires_semi_to_be_stmt_FIXME(innermost) { + if match innermost.kind { + ExprKind::MacCall(_) => false, + _ => !classify::expr_requires_semi_to_be_stmt(innermost), + } { return true; } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 951c3495995c..5f7bd0835d3d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -498,7 +498,10 @@ impl<'a> Parser<'a> { /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) - && !classify::expr_requires_semi_to_be_stmt_FIXME(e) + && match e.kind { + ExprKind::MacCall(_) => false, + _ => !classify::expr_requires_semi_to_be_stmt(e), + } } /// Parses `x..y`, `x..=y`, and `x..`/`x..=`. @@ -2694,7 +2697,10 @@ impl<'a> Parser<'a> { // If it's not a free-standing expression, and is followed by a block, // then it's very likely the condition to an `else if`. if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) - && classify::expr_requires_semi_to_be_stmt_FIXME(&cond) => + && match cond.kind { + ExprKind::MacCall(_) => true, + _ => classify::expr_requires_semi_to_be_stmt(&cond), + } => { self.dcx().emit_err(errors::ExpectedElseBlock { first_tok_span, @@ -3136,8 +3142,10 @@ impl<'a> Parser<'a> { err })?; - let require_comma = classify::expr_requires_semi_to_be_stmt_FIXME(&expr) - && this.token != token::CloseDelim(Delimiter::Brace); + let require_comma = match expr.kind { + ExprKind::MacCall(_) => true, + _ => classify::expr_requires_semi_to_be_stmt(&expr), + } && this.token != token::CloseDelim(Delimiter::Brace); if !require_comma { arm_body = Some(expr); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index f64a480a18c3..684799eb6a78 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -648,8 +648,10 @@ impl<'a> Parser<'a> { match &mut stmt.kind { // Expression without semicolon. StmtKind::Expr(expr) - if classify::expr_requires_semi_to_be_stmt_FIXME(expr) - && !expr.attrs.is_empty() + if match expr.kind { + ExprKind::MacCall(_) => true, + _ => classify::expr_requires_semi_to_be_stmt(expr), + } && !expr.attrs.is_empty() && ![token::Eof, token::Semi, token::CloseDelim(Delimiter::Brace)] .contains(&self.token.kind) => { @@ -663,7 +665,10 @@ impl<'a> Parser<'a> { // Expression without semicolon. StmtKind::Expr(expr) if self.token != token::Eof - && classify::expr_requires_semi_to_be_stmt_FIXME(expr) => + && match expr.kind { + ExprKind::MacCall(_) => true, + _ => classify::expr_requires_semi_to_be_stmt(expr), + } => { // Just check for errors and recover; do not eat semicolon yet.