diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 984b280e81b5a..0ecf57cfc4c94 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1185,7 +1185,7 @@ impl Stmt { pub fn has_trailing_semicolon(&self) -> bool { match &self.kind { StmtKind::Semi(_) => true, - StmtKind::MacCall(mac) => matches!(mac.style, MacStmtStyle::Semicolon), + StmtKind::MacCall(mac) => matches!(mac.style, MacStmtStyle::Semicolon(_)), _ => false, } } @@ -1197,11 +1197,14 @@ impl Stmt { /// `LazyAttrTokenStream`. The parser is responsible for calling /// `ToAttrTokenStream::add_trailing_semi` when there is actually /// a semicolon in the tokenstream. - pub fn add_trailing_semicolon(mut self) -> Self { + pub fn add_trailing_semicolon(mut self, semi_span: Span) -> Self { + if let Some(mac_span) = self.span.find_ancestor_in_same_ctxt(semi_span) { + self.span = mac_span.to(semi_span); + } self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), StmtKind::MacCall(mut mac) => { - mac.style = MacStmtStyle::Semicolon; + mac.style = MacStmtStyle::Semicolon(semi_span); StmtKind::MacCall(mac) } kind => kind, @@ -1231,11 +1234,17 @@ pub enum StmtKind { /// Expr with a trailing semi-colon. Semi(P), /// Just a trailing semi-colon. - Empty, + Empty(EmptyFromMacro), /// Macro. MacCall(P), } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum EmptyFromMacro { + Yes, + No, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct MacCallStmt { pub mac: P, @@ -1248,7 +1257,7 @@ pub struct MacCallStmt { pub enum MacStmtStyle { /// The macro statement had a trailing semicolon (e.g., `foo! { ... };` /// `foo!(...);`, `foo![...];`). - Semicolon, + Semicolon(Span), /// The macro statement had braces (e.g., `foo! { ... }`). Braces, /// The macro statement had parentheses or brackets and no semicolon (e.g., diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 9d91f41d6c799..534ee65531012 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -134,7 +134,7 @@ impl HasTokens for StmtKind { StmtKind::Let(local) => local.tokens.as_ref(), StmtKind::Item(item) => item.tokens(), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(), - StmtKind::Empty => None, + StmtKind::Empty(_) => None, StmtKind::MacCall(mac) => mac.tokens.as_ref(), } } @@ -143,7 +143,7 @@ impl HasTokens for StmtKind { StmtKind::Let(local) => Some(&mut local.tokens), StmtKind::Item(item) => item.tokens_mut(), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(), - StmtKind::Empty => None, + StmtKind::Empty(_) => None, StmtKind::MacCall(mac) => Some(&mut mac.tokens), } } @@ -277,7 +277,7 @@ impl HasAttrs for StmtKind { StmtKind::Let(local) => &local.attrs, StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(), StmtKind::Item(item) => item.attrs(), - StmtKind::Empty => &[], + StmtKind::Empty(_) => &[], StmtKind::MacCall(mac) => &mac.attrs, } } @@ -287,7 +287,7 @@ impl HasAttrs for StmtKind { StmtKind::Let(local) => f(&mut local.attrs), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), StmtKind::Item(item) => item.visit_attrs(f), - StmtKind::Empty => {} + StmtKind::Empty(_) => {} StmtKind::MacCall(mac) => f(&mut mac.attrs), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 06708e2e703ac..38703a6298afd 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -372,7 +372,7 @@ fn walk_flat_map_stmt_kind(vis: &mut T, kind: StmtKind) -> SmallV StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(), StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(), StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), - StmtKind::Empty => smallvec![StmtKind::Empty], + StmtKind::Empty(from_macro) => smallvec![StmtKind::Empty(from_macro)], StmtKind::MacCall(mut mac) => { let MacCallStmt { mac: mac_, style: _, attrs, tokens: _ } = mac.deref_mut(); for attr in attrs { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ab15cb28fa12d..5e5cac3359547 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -428,6 +428,7 @@ macro_rules! common_visitor_and_walkers { DelegationMac, DelimArgs, DelimSpan, + EmptyFromMacro, EnumDef, Extern, ForLoopKind, @@ -1166,7 +1167,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V: StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), StmtKind::Item(item) => try_visit!(visitor.visit_item(item)), StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)), - StmtKind::Empty => {} + StmtKind::Empty(_) => {} StmtKind::MacCall(mac) => { let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac; walk_list!(visitor, visit_attribute, attrs); diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 2cc07694afbc9..d461a306af90b 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -75,7 +75,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let span = self.lower_span(s.span); stmts.push(hir::Stmt { hir_id, kind, span }); } - StmtKind::Empty => {} + StmtKind::Empty(_) => {} StmtKind::MacCall(..) => panic!("shouldn't exist here"), } ast_stmts = tail; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f0cf0c1487f78..e071f9f8c044d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1446,7 +1446,7 @@ impl<'a> State<'a> { self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt()); self.word(";"); } - ast::StmtKind::Empty => { + ast::StmtKind::Empty(_) => { self.space_if_not_bol(); self.word(";"); } @@ -1454,7 +1454,7 @@ impl<'a> State<'a> { self.space_if_not_bol(); self.print_outer_attributes(&mac.attrs); self.print_mac(&mac.mac); - if mac.style == ast::MacStmtStyle::Semicolon { + if matches!(mac.style, ast::MacStmtStyle::Semicolon(_)) { self.word(";"); } } diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index ea7248ca5393a..11c257462e869 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -393,7 +393,7 @@ impl<'cx, 'a> Context<'cx, 'a> { )], self.span, )) - .add_trailing_semicolon(); + .add_trailing_semicolon(self.span.shrink_to_hi()); let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind)); let rslt = if self.is_consumed { let ret = self.cx.stmt_expr(local_bind_path); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c01320fc6446d..d197dbeef92e1 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -124,7 +124,7 @@ impl Annotatable { Annotatable::AssocItem(node, _) => TokenStream::from_ast(node), Annotatable::ForeignItem(node) => TokenStream::from_ast(node), Annotatable::Stmt(node) => { - assert!(!matches!(node.kind, ast::StmtKind::Empty)); + assert!(!matches!(node.kind, ast::StmtKind::Empty(_))); TokenStream::from_ast(node) } Annotatable::Expr(node) => TokenStream::from_ast(node), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0517fd0419d28..349baf01d30e9 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1204,7 +1204,7 @@ macro_rules! assign_id { } enum AddSemicolon { - Yes, + Yes(Span), No, } @@ -1687,7 +1687,7 @@ impl InvocationCollectorNode for ast::Stmt { StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)), StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)), StmtKind::Expr(..) => unreachable!(), - StmtKind::Let(..) | StmtKind::Empty => false, + StmtKind::Let(..) | StmtKind::Empty(_) => false, } } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { @@ -1696,23 +1696,32 @@ impl InvocationCollectorNode for ast::Stmt { let (add_semicolon, mac, attrs) = match self.kind { StmtKind::MacCall(mac) => { let ast::MacCallStmt { mac, style, attrs, .. } = *mac; - (style == MacStmtStyle::Semicolon, mac, attrs) + let add_semicolon = match style { + MacStmtStyle::Semicolon(span) => AddSemicolon::Yes(span), + MacStmtStyle::Braces | MacStmtStyle::NoBraces => AddSemicolon::No, + }; + (add_semicolon, mac, attrs) } StmtKind::Item(item) => match *item { ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { - (mac.args.need_semicolon(), mac, attrs) + (AddSemicolon::No, mac, attrs) } _ => unreachable!(), }, StmtKind::Semi(expr) => match *expr { - ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => { - (mac.args.need_semicolon(), mac, attrs) + ast::Expr { kind: ExprKind::MacCall(mac), attrs, span: expr_span, .. } => { + let add_semicolon = if mac.args.need_semicolon() { + AddSemicolon::Yes(expr_span.shrink_to_hi().to(self.span)) + } else { + AddSemicolon::No + }; + (add_semicolon, mac, attrs) } _ => unreachable!(), }, _ => unreachable!(), }; - (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No }) + (mac, attrs, add_semicolon) } fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { match &self.kind { @@ -1735,9 +1744,9 @@ impl InvocationCollectorNode for ast::Stmt { fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) { // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. - if matches!(add_semicolon, AddSemicolon::Yes) { + if let AddSemicolon::Yes(semi_span) = add_semicolon { if let Some(stmt) = stmts.pop() { - stmts.push(stmt.add_trailing_semicolon()); + stmts.push(stmt.add_trailing_semicolon(semi_span)); } } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 174844d6ad639..0c007b3805a06 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -431,7 +431,7 @@ fn transcribe_metavar<'tx>( mk_delimited(block.span, MetaVarKind::Block, TokenStream::from_ast(block)) } MatchedSingle(ParseNtResult::Stmt(stmt)) => { - let stream = if let StmtKind::Empty = stmt.kind { + let stream = if let StmtKind::Empty(_) = stmt.kind { // FIXME: Properly collect tokens for empty statements. TokenStream::token_alone(token::Semi, stmt.span) } else { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 6e1c6df4bcb40..5151578159834 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -2,7 +2,7 @@ use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::visit::AssocCtxt; -use rustc_ast::{self as ast, Safety}; +use rustc_ast::{self as ast, EmptyFromMacro, Safety}; use rustc_data_structures::fx::FxHashMap; use rustc_span::{DUMMY_SP, Ident}; use smallvec::{SmallVec, smallvec}; @@ -359,7 +359,7 @@ impl MutVisitor for PlaceholderExpander { _ => return walk_flat_map_stmt(self, stmt), }; - if style == ast::MacStmtStyle::Semicolon { + if let ast::MacStmtStyle::Semicolon(semi_span) = style { // Implement the proposal described in // https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449 // @@ -379,17 +379,18 @@ impl MutVisitor for PlaceholderExpander { // 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 }; + let empty_stmt = ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Empty(EmptyFromMacro::Yes), + span: semi_span, + }; if let Some(stmt) = stmts.pop() { if stmt.has_trailing_semicolon() { stmts.push(stmt); stmts.push(empty_stmt); } else { - stmts.push(stmt.add_trailing_semicolon()); + stmts.push(stmt.add_trailing_semicolon(semi_span)); } } else { stmts.push(empty_stmt); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 152971c4ed691..6e90c8d92d79f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -845,7 +845,7 @@ impl EarlyLintPass for UnusedDocComment { // Disabled pending discussion in #78306 ast::StmtKind::Item(..) => return, // expressions will be reported by `check_expr`. - ast::StmtKind::Empty + ast::StmtKind::Empty(_) | ast::StmtKind::Semi(_) | ast::StmtKind::Expr(_) | ast::StmtKind::MacCall(_) => return, diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index f6d2fbe42618e..362a6012e67ce 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -1,4 +1,4 @@ -use rustc_ast::{Block, StmtKind}; +use rustc_ast::{Block, EmptyFromMacro, StmtKind}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::Span; @@ -33,8 +33,10 @@ impl EarlyLintPass for RedundantSemicolons { let mut seq = None; for stmt in block.stmts.iter() { match (&stmt.kind, &mut seq) { - (StmtKind::Empty, None) => seq = Some((stmt.span, false)), - (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true), + (StmtKind::Empty(EmptyFromMacro::No), None) => seq = Some((stmt.span, false)), + (StmtKind::Empty(EmptyFromMacro::No), Some(seq)) => { + *seq = (seq.0.to(stmt.span), true) + } (_, seq) => maybe_lint_redundant_semis(cx, seq), } } @@ -44,10 +46,6 @@ impl EarlyLintPass for RedundantSemicolons { fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) { if let Some((span, multiple)) = seq.take() { - if span == rustc_span::DUMMY_SP { - return; - } - // Ignore redundant semicolons inside macro expansion.(issue #142143) let suggestion = if span.from_expansion() { None diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 2fa6520f2a42a..7a659c5aed404 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -3,13 +3,13 @@ use std::mem; use std::ops::Bound; use ast::Label; -use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::util::classify::{self, TrailingBrace}; use rustc_ast::{ - AttrStyle, AttrVec, Block, BlockCheckMode, DUMMY_NODE_ID, Expr, ExprKind, HasAttrs, Local, - LocalKind, MacCall, MacCallStmt, MacStmtStyle, Recovered, Stmt, StmtKind, + self as ast, AttrStyle, AttrVec, Block, BlockCheckMode, DUMMY_NODE_ID, EmptyFromMacro, Expr, + ExprKind, HasAttrs, Local, LocalKind, MacCall, MacCallStmt, MacStmtStyle, Recovered, Stmt, + StmtKind, }; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{BytePos, ErrorGuaranteed, Ident, Span, kw, sym}; @@ -161,7 +161,7 @@ impl<'a> Parser<'a> { } else if self.eat(exp!(Semi)) { // Do not attempt to parse an expression if we're done here. self.error_outer_attrs(attrs); - self.mk_stmt(lo, StmtKind::Empty) + self.mk_stmt(lo, StmtKind::Empty(EmptyFromMacro::No)) } else if self.token != token::CloseBrace { // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case // above. @@ -548,7 +548,7 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| t == &token::OpenBrace)) || do_not_suggest_help => {} // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836). - Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {} + Ok(Some(Stmt { kind: StmtKind::Empty(_), .. })) => {} Ok(Some(stmt)) => { let stmt_own_line = self.psess.source_map().is_line_before_span_empty(sp); let stmt_span = if stmt_own_line && self.eat(exp!(Semi)) { @@ -1032,13 +1032,13 @@ impl<'a> Parser<'a> { } eat_semi = false; } - StmtKind::Empty | StmtKind::Item(_) | StmtKind::Let(_) | StmtKind::Semi(_) => { + StmtKind::Empty(_) | StmtKind::Item(_) | StmtKind::Let(_) | StmtKind::Semi(_) => { eat_semi = false } } if add_semi_to_stmt || (eat_semi && self.eat(exp!(Semi))) { - stmt = stmt.add_trailing_semicolon(); + stmt = stmt.add_trailing_semicolon(self.prev_token.span); } stmt.span = stmt.span.to(self.prev_token.span); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index d93151497986c..26fa3534916f1 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1074,30 +1074,6 @@ impl SourceMap { let source_file = &self.files()[source_file_index]; source_file.is_imported() } - - /// Gets the span of a statement. If the statement is a macro expansion, the - /// span in the context of the block span is found. The trailing semicolon is included - /// on a best-effort basis. - pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span { - if !stmt_span.from_expansion() { - return stmt_span; - } - let mac_call = original_sp(stmt_span, block_span); - self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi())) - } - - /// Tries to find the span of the semicolon of a macro call statement. - /// The input must be the *call site* span of a statement from macro expansion. - /// ```ignore (illustrative) - /// // v output - /// mac!(); - /// // ^^^^^^ input - /// ``` - pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option { - let span = self.span_extend_while_whitespace(mac_call); - let span = self.next_point(span); - if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None } - } } pub fn get_source_map() -> Option> { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 44baa213b2847..486031c55654c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -809,17 +809,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } _ => return None, }; - let span = if last_stmt.span.from_expansion() { - let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span); - self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? - } else { - self.tcx - .sess - .source_map() - .span_extend_while_whitespace(last_expr.span) - .shrink_to_hi() - .with_hi(last_stmt.span.hi()) - }; + + let expr_span = last_expr.span.find_ancestor_inside_same_ctxt(last_stmt.span)?; + let span = self + .tcx + .sess + .source_map() + .span_extend_while_whitespace(expr_span) + .shrink_to_hi() + .with_hi(last_stmt.span.hi()); Some((span, needs_box)) } @@ -904,15 +902,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { [(ident, _ty)] => { let sm = self.tcx.sess.source_map(); let (span, sugg) = if let Some(stmt) = blk.stmts.last() { - let stmt_span = sm.stmt_span(stmt.span, blk.span); let sugg = if sm.is_multiline(blk.span) - && let Some(spacing) = sm.indentation_before(stmt_span) + && let Some(spacing) = sm.indentation_before(stmt.span) { format!("\n{spacing}{ident}") } else { format!(" {ident}") }; - (stmt_span.shrink_to_hi(), sugg) + (stmt.span.shrink_to_hi(), sugg) } else { let sugg = if sm.is_multiline(blk.span) && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo()) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index f229f77c97846..c8c3bf4ab4b83 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -591,7 +591,9 @@ fn parse_source( } has_non_items = true; } - StmtKind::Let(_) | StmtKind::Semi(_) | StmtKind::Empty => has_non_items = true, + StmtKind::Let(_) | StmtKind::Semi(_) | StmtKind::Empty(_) => { + has_non_items = true + } } // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index f6c128d4c5298..ab6b7af459bb1 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -101,22 +101,9 @@ impl SemicolonBlock { ); } - fn semicolon_outside_block(&self, cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>) { + fn semicolon_outside_block(&self, cx: &LateContext<'_>, block: &Block<'_>, remove_span: Span) { let insert_span = block.span.with_lo(block.span.hi()); - // For macro call semicolon statements (`mac!();`), the statement's span does not actually - // include the semicolon itself, so use `mac_call_stmt_semi_span`, which finds the semicolon - // based on a source snippet. - // (Does not use `stmt_span` as that requires `.from_expansion()` to return true, - // which is not the case for e.g. `line!();` and `asm!();`) - let Some(remove_span) = cx - .sess() - .source_map() - .mac_call_stmt_semi_span(tail_stmt_expr.span.source_callsite()) - else { - return; - }; - if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) { return; } @@ -159,6 +146,14 @@ impl LateLintPass<'_> for SemicolonBlock { else { return; }; + let expr_span = expr.span.find_ancestor_inside_same_ctxt(stmt.span)?; + let remove_span = cx + .tcx + .sess + .source_map() + .span_extend_while_whitespace(expr_span) + .shrink_to_hi() + .with_hi(stmt.span.hi()); self.semicolon_outside_block(cx, block, expr); }, StmtKind::Semi(Expr { diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 381c938ae8062..b71cf59b3bb25 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -31,7 +31,7 @@ pub(crate) fn get_span_without_attrs(stmt: &ast::Stmt) -> Span { ast::StmtKind::Item(ref item) => item.span, ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => expr.span, ast::StmtKind::MacCall(ref mac_stmt) => mac_stmt.mac.span(), - ast::StmtKind::Empty => stmt.span, + ast::StmtKind::Empty(_) => stmt.span, } } diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 08aedff2b20da..70c0aac643ac9 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1248,7 +1248,7 @@ fn block_has_statements(block: &ast::Block) -> bool { block .stmts .iter() - .any(|stmt| !matches!(stmt.kind, ast::StmtKind::Empty)) + .any(|stmt| !matches!(stmt.kind, ast::StmtKind::Empty(_))) } /// Checks whether a block contains no statements, expressions, comments, or diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index ac132999b62eb..09c2311901228 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -75,7 +75,7 @@ impl Spanned for ast::Stmt { mk_sp(mac_stmt.attrs[0].span.lo(), self.span.hi()) } } - ast::StmtKind::Empty => self.span, + ast::StmtKind::Empty(_) => self.span, } } } diff --git a/src/tools/rustfmt/src/stmt.rs b/src/tools/rustfmt/src/stmt.rs index 2788159018d0d..4a1e569e07f4a 100644 --- a/src/tools/rustfmt/src/stmt.rs +++ b/src/tools/rustfmt/src/stmt.rs @@ -68,7 +68,7 @@ impl<'a> Stmt<'a> { } pub(crate) fn is_empty(&self) -> bool { - matches!(self.inner.kind, ast::StmtKind::Empty) + matches!(self.inner.kind, ast::StmtKind::Empty(_)) } fn is_last_expr(&self) -> bool { @@ -137,7 +137,7 @@ fn format_stmt( .max_width_error(shape.width, ex.span())?; format_expr(ex, expr_type, context, shape).map(|s| s + suffix) } - ast::StmtKind::MacCall(..) | ast::StmtKind::Item(..) | ast::StmtKind::Empty => { + ast::StmtKind::MacCall(..) | ast::StmtKind::Item(..) | ast::StmtKind::Empty(_) => { Err(RewriteError::Unknown) } }; diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index f6a9a3f2cd175..ad6902c275c58 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -176,7 +176,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } self.format_missing(stmt.span().hi()); } - ast::StmtKind::Empty => (), + ast::StmtKind::Empty(_) => (), } } @@ -908,7 +908,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let include_next_empty = if stmts.len() > 1 { matches!( (&stmts[0].as_ast_node().kind, &stmts[1].as_ast_node().kind), - (ast::StmtKind::Item(_), ast::StmtKind::Empty) + (ast::StmtKind::Item(_), ast::StmtKind::Empty(_)) ) } else { false diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index b94a09bb92ed9..b12b68a509ed4 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -156,7 +156,7 @@ LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | naked_asm!(""); - | -------------- multiple `naked_asm!` invocations are not allowed in naked functions + | --------------- multiple `naked_asm!` invocations are not allowed in naked functions error: referencing function parameters is not allowed in naked functions --> $DIR/naked-functions.rs:96:11 diff --git a/tests/ui/asm/x86_64/goto.stderr b/tests/ui/asm/x86_64/goto.stderr index 78b726b3f3d31..f3bc3cdb02867 100644 --- a/tests/ui/asm/x86_64/goto.stderr +++ b/tests/ui/asm/x86_64/goto.stderr @@ -10,7 +10,7 @@ LL | | options(noreturn) LL | | ); | |_________- any code following this expression is unreachable LL | unreachable!(); - | ^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/goto.rs:133:8 diff --git a/tests/ui/async-await/unreachable-lint-2.stderr b/tests/ui/async-await/unreachable-lint-2.stderr index cbebc9951f32d..d4873310618b3 100644 --- a/tests/ui/async-await/unreachable-lint-2.stderr +++ b/tests/ui/async-await/unreachable-lint-2.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | endless().await; | ----- any code following this expression is unreachable LL | println!("this is unreachable!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/unreachable-lint-2.rs:3:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/block-result/issue-13428.stderr b/tests/ui/block-result/issue-13428.stderr index c119b69da2294..43c2ca3d50bfc 100644 --- a/tests/ui/block-result/issue-13428.stderr +++ b/tests/ui/block-result/issue-13428.stderr @@ -1,10 +1,15 @@ error[E0308]: mismatched types --> $DIR/issue-13428.rs:3:13 | -LL | fn foo() -> String { - | --- ^^^^^^ expected `String`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression +LL | fn foo() -> String { + | --- ^^^^^^ expected `String`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +... +LL | / // Put the trailing semicolon on its own line to test that the +LL | | // note message gets the offending semicolon exactly +LL | | ; + | |_____- help: remove this semicolon to return this value error[E0308]: mismatched types --> $DIR/issue-13428.rs:11:13 diff --git a/tests/ui/lint/dead-code/closure-bang.stderr b/tests/ui/lint/dead-code/closure-bang.stderr index a0f5962dfe024..6643d18b43f49 100644 --- a/tests/ui/lint/dead-code/closure-bang.stderr +++ b/tests/ui/lint/dead-code/closure-bang.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | x(); | --- any code following this expression is unreachable LL | println!("Foo bar"); - | ^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/closure-bang.rs:1:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs index 4360eb964a4af..69bf56a79f34a 100644 --- a/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs +++ b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs @@ -3,9 +3,9 @@ #![deny(redundant_semicolons)] macro_rules! m { - ($stmt:stmt) => { #[allow(bad_style)] $stmt } //~ ERROR unnecessary trailing semicolon [redundant_semicolons] + ($stmt:stmt) => { #[allow(bad_style)] $stmt } } fn main() { - m!(;); + m!(;); //~ ERROR unnecessary trailing semicolon [redundant_semicolons] } diff --git a/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr index 7a38ec318ab6a..d0240ecb2c5bd 100644 --- a/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr +++ b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr @@ -1,18 +1,14 @@ error: unnecessary trailing semicolon - --> $DIR/suggest-remove-semi-in-macro-expansion-issue-142143.rs:6:43 + --> $DIR/suggest-remove-semi-in-macro-expansion-issue-142143.rs:10:5 | -LL | ($stmt:stmt) => { #[allow(bad_style)] $stmt } - | ^^^^^ -... LL | m!(;); - | ----- in this macro invocation + | ^^^^^^ help: remove this semicolon | note: the lint level is defined here --> $DIR/suggest-remove-semi-in-macro-expansion-issue-142143.rs:3:9 | LL | #![deny(redundant_semicolons)] | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/liveness/liveness-return-last-stmt-semi.stderr b/tests/ui/liveness/liveness-return-last-stmt-semi.stderr index de0843aa637f3..bde45aed1d293 100644 --- a/tests/ui/liveness/liveness-return-last-stmt-semi.stderr +++ b/tests/ui/liveness/liveness-return-last-stmt-semi.stderr @@ -28,8 +28,9 @@ error[E0308]: mismatched types --> $DIR/liveness-return-last-stmt-semi.rs:3:41 | LL | macro_rules! test { () => { fn foo() -> i32 { 1; } } } - | --- ^^^ expected `i32`, found `()` - | | + | --- ^^^ - help: remove this semicolon to return this value + | | | + | | expected `i32`, found `()` | implicitly returns `()` as its body has no tail or `return` expression ... LL | test!(); diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr index afb929454c7da..752cab775aa29 100644 --- a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -4,7 +4,7 @@ error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to return `()` LL | let error = Closure::wrap(Box::new(move || { | ------- this closure LL | panic!("Can't connect to server."); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!` | = note: expected unit type `()` found type `!` diff --git a/tests/ui/reachable/expr_again.stderr b/tests/ui/reachable/expr_again.stderr index 5dec512ba5def..8ef63ffe76ef6 100644 --- a/tests/ui/reachable/expr_again.stderr +++ b/tests/ui/reachable/expr_again.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | continue; | -------- any code following this expression is unreachable LL | println!("hi"); - | ^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/expr_again.rs:3:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/reachable/expr_block.stderr b/tests/ui/reachable/expr_block.stderr index d5f248a24910e..4d999505abb93 100644 --- a/tests/ui/reachable/expr_block.stderr +++ b/tests/ui/reachable/expr_block.stderr @@ -18,9 +18,7 @@ error: unreachable statement LL | return; | ------ any code following this expression is unreachable LL | println!("foo"); - | ^^^^^^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^ unreachable statement error: aborting due to 2 previous errors diff --git a/tests/ui/reachable/expr_if.stderr b/tests/ui/reachable/expr_if.stderr index ebd0b5a3ebefc..e6a5382460ec9 100644 --- a/tests/ui/reachable/expr_if.stderr +++ b/tests/ui/reachable/expr_if.stderr @@ -22,9 +22,7 @@ LL | return; | ------ any code following this expression is unreachable ... LL | println!("But I am."); - | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement error: aborting due to 2 previous errors diff --git a/tests/ui/reachable/expr_loop.stderr b/tests/ui/reachable/expr_loop.stderr index 9185846860507..826e4daeea56f 100644 --- a/tests/ui/reachable/expr_loop.stderr +++ b/tests/ui/reachable/expr_loop.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | loop { return; } | ------ any code following this expression is unreachable LL | println!("I am dead."); - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/expr_loop.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: unreachable statement --> $DIR/expr_loop.rs:21:5 @@ -19,9 +18,7 @@ error: unreachable statement LL | loop { return; } | ------ any code following this expression is unreachable LL | println!("I am dead."); - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement error: unreachable statement --> $DIR/expr_loop.rs:32:5 @@ -29,9 +26,7 @@ error: unreachable statement LL | loop { 'middle: loop { loop { break 'middle; } } } | -------------------------------------------------- any code following this expression is unreachable LL | println!("I am dead."); - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement error: aborting due to 3 previous errors diff --git a/tests/ui/reachable/expr_match.stderr b/tests/ui/reachable/expr_match.stderr index ae202a6e0c34a..34bae65adf131 100644 --- a/tests/ui/reachable/expr_match.stderr +++ b/tests/ui/reachable/expr_match.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | match () { () => return } | ------------------------- any code following this `match` expression is unreachable, as all arms diverge LL | println!("I am dead"); - | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/expr_match.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: unreachable statement --> $DIR/expr_match.rs:19:5 @@ -19,9 +18,7 @@ error: unreachable statement LL | match () { () if false => return, () => return } | ------------------------------------------------ any code following this `match` expression is unreachable, as all arms diverge LL | println!("I am dead"); - | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement error: unreachable expression --> $DIR/expr_match.rs:25:25 @@ -41,9 +38,7 @@ LL | | () => return, LL | | } | |_____- any code following this `match` expression is unreachable, as all arms diverge LL | println!("I am dead"); - | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement error: aborting due to 4 previous errors diff --git a/tests/ui/reachable/unreachable-code-ret.stderr b/tests/ui/reachable/unreachable-code-ret.stderr index d86def536df8d..7a82cf505cd77 100644 --- a/tests/ui/reachable/unreachable-code-ret.stderr +++ b/tests/ui/reachable/unreachable-code-ret.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | return; | ------ any code following this expression is unreachable LL | println!("Paul is dead"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/unreachable-code-ret.rs:1:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr index c33a5855d5068..c9eb393b7ea68 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr @@ -4,14 +4,13 @@ error: unreachable statement LL | fn never_arg(!: Void) -> u32 { | - any code following a never pattern is unreachable LL | println!(); - | ^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/diverge-causes-unreachable-code.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: unreachable statement --> $DIR/diverge-causes-unreachable-code.rs:16:5 @@ -19,9 +18,7 @@ error: unreachable statement LL | fn ref_never_arg(&!: &Void) -> u32 { | -- any code following a never pattern is unreachable LL | println!(); - | ^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^ unreachable statement error: unreachable statement --> $DIR/diverge-causes-unreachable-code.rs:25:5 @@ -30,9 +27,7 @@ LL | let ! = *ptr; | - any code following a never pattern is unreachable LL | } LL | println!(); - | ^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^ unreachable statement error: unreachable statement --> $DIR/diverge-causes-unreachable-code.rs:34:5 @@ -41,9 +36,7 @@ LL | match *ptr { ! }; | ---------------- any code following this `match` expression is unreachable, as all arms diverge LL | } LL | println!(); - | ^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^ unreachable statement error: aborting due to 4 previous errors diff --git a/tests/ui/unpretty/interpolation-expanded.stdout b/tests/ui/unpretty/interpolation-expanded.stdout index 7284a89e7a9b0..2819e840eeba4 100644 --- a/tests/ui/unpretty/interpolation-expanded.stdout +++ b/tests/ui/unpretty/interpolation-expanded.stdout @@ -61,20 +61,16 @@ fn local() { macro_rules! let_expr_else_return { ($pat:pat, $expr:expr) => { let $pat = $expr else { return; }; }; } - let - no_paren = void() else { return; }; + let no_paren = void() else { return; }; } fn match_arm() { macro_rules! match_arm { ($pat:pat, $expr:expr) => { match () { $pat => $expr } }; } - match () { - - no_paren => 1 - 1, - }; + match () { no_paren => 1 - 1, }; match () { paren_around_brace => ({ 1 }) - 1, }; } @@ -99,6 +95,6 @@ fn vis_inherited() { macro_rules! vis_inherited { ($vis:vis struct) => { $vis struct Struct; }; } - struct Struct; + struct Struct; }