Skip to content

Commit 1d82a25

Browse files
committed
Auto merge of #69506 - Centril:stmt-semi-none, r=<try>
encode `;` stmt without expr as `StmtKind::Semi(None)` Instead of encoding `;` statements without a an expression as a tuple in AST, we modify `ast::StmtKind::Semi` to accept an `Option<_>` and then encode the `;` with `StmtKind::Semi(None)`. r? @petrochenkov
2 parents 0c15adc + fcea184 commit 1d82a25

File tree

13 files changed

+59
-88
lines changed

13 files changed

+59
-88
lines changed

src/librustc_ast_lowering/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12671267
)
12681268
}
12691269

1270-
fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
1270+
pub(super) fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
12711271
self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), ThinVec::new()))
12721272
}
12731273

src/librustc_ast_lowering/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2280,7 +2280,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
22802280
.collect();
22812281
}
22822282
StmtKind::Expr(ref e) => hir::StmtKind::Expr(self.lower_expr(e)),
2283-
StmtKind::Semi(ref e) => hir::StmtKind::Semi(self.lower_expr(e)),
2283+
StmtKind::Semi(Some(ref e)) => hir::StmtKind::Semi(self.lower_expr(e)),
2284+
StmtKind::Semi(None) => hir::StmtKind::Semi(self.expr_unit(s.span)),
22842285
StmtKind::Mac(..) => panic!("shouldn't exist here"),
22852286
};
22862287
smallvec![hir::Stmt { hir_id: self.lower_node_id(s.id), kind, span: s.span }]

src/librustc_ast_pretty/pprust.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -1446,19 +1446,11 @@ impl<'a> State<'a> {
14461446
}
14471447
}
14481448
ast::StmtKind::Semi(ref expr) => {
1449-
match expr.kind {
1450-
// Filter out empty `Tup` exprs created for the `redundant_semicolon`
1451-
// lint, as they shouldn't be visible and interact poorly
1452-
// with proc macros.
1453-
ast::ExprKind::Tup(ref exprs) if exprs.is_empty() && expr.attrs.is_empty() => {
1454-
()
1455-
}
1456-
_ => {
1457-
self.space_if_not_bol();
1458-
self.print_expr_outer_attr_style(expr, false);
1459-
self.s.word(";");
1460-
}
1449+
self.space_if_not_bol();
1450+
if let Some(expr) = expr {
1451+
self.print_expr_outer_attr_style(expr, false);
14611452
}
1453+
self.s.word(";");
14621454
}
14631455
ast::StmtKind::Mac(ref mac) => {
14641456
let (ref mac, style, ref attrs) = **mac;
+25-34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{EarlyContext, EarlyLintPass, LintContext};
22
use rustc_errors::Applicability;
3-
use syntax::ast::{ExprKind, Stmt, StmtKind};
3+
use rustc_span::Span;
4+
use syntax::ast::{Block, StmtKind};
45

56
declare_lint! {
67
pub REDUNDANT_SEMICOLON,
@@ -11,40 +12,30 @@ declare_lint! {
1112
declare_lint_pass!(RedundantSemicolon => [REDUNDANT_SEMICOLON]);
1213

1314
impl EarlyLintPass for RedundantSemicolon {
14-
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
15-
if let StmtKind::Semi(expr) = &stmt.kind {
16-
if let ExprKind::Tup(ref v) = &expr.kind {
17-
if v.is_empty() {
18-
// Strings of excess semicolons are encoded as empty tuple expressions
19-
// during the parsing stage, so we check for empty tuple expressions
20-
// which span only semicolons
21-
if let Ok(source_str) = cx.sess().source_map().span_to_snippet(stmt.span) {
22-
if source_str.chars().all(|c| c == ';') {
23-
let multiple = (stmt.span.hi() - stmt.span.lo()).0 > 1;
24-
let msg = if multiple {
25-
"unnecessary trailing semicolons"
26-
} else {
27-
"unnecessary trailing semicolon"
28-
};
29-
cx.struct_span_lint(REDUNDANT_SEMICOLON, stmt.span, |lint| {
30-
let mut err = lint.build(&msg);
31-
let suggest_msg = if multiple {
32-
"remove these semicolons"
33-
} else {
34-
"remove this semicolon"
35-
};
36-
err.span_suggestion(
37-
stmt.span,
38-
&suggest_msg,
39-
String::new(),
40-
Applicability::MaybeIncorrect,
41-
);
42-
err.emit();
43-
});
44-
}
45-
}
46-
}
15+
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
16+
let mut seq = None;
17+
for stmt in block.stmts.iter() {
18+
match (&stmt.kind, &mut seq) {
19+
(StmtKind::Semi(None), None) => seq = Some((stmt.span, false)),
20+
(StmtKind::Semi(None), Some(seq)) => *seq = (seq.0.to(stmt.span), true),
21+
(_, seq) => maybe_lint_redundant_semis(cx, seq),
4722
}
4823
}
24+
maybe_lint_redundant_semis(cx, &mut seq);
25+
}
26+
}
27+
28+
fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
29+
if let Some((span, multiple)) = seq.take() {
30+
cx.struct_span_lint(REDUNDANT_SEMICOLON, span, |lint| {
31+
let (msg, rem) = if multiple {
32+
("unnecessary trailing semicolons", "remove these semicolons")
33+
} else {
34+
("unnecessary trailing semicolon", "remove this semicolon")
35+
};
36+
lint.build(msg)
37+
.span_suggestion(span, rem, String::new(), Applicability::MaybeIncorrect)
38+
.emit();
39+
});
4940
}
5041
}

src/librustc_parse/parser/stmt.rs

+7-20
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,10 @@ impl<'a> Parser<'a> {
5959
} else if let Some(item) = self.parse_stmt_item(attrs.clone())? {
6060
// FIXME: Bad copy of attrs
6161
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
62-
} else if self.token == token::Semi {
62+
} else if self.eat(&token::Semi) {
6363
// Do not attempt to parse an expression if we're done here.
6464
self.error_outer_attrs(&attrs);
65-
self.bump();
66-
let mut last_semi = lo;
67-
while self.token == token::Semi {
68-
last_semi = self.token.span;
69-
self.bump();
70-
}
71-
// We are encoding a string of semicolons as an an empty tuple that spans
72-
// the excess semicolons to preserve this info until the lint stage.
73-
let kind = StmtKind::Semi(self.mk_expr(
74-
lo.to(last_semi),
75-
ExprKind::Tup(Vec::new()),
76-
AttrVec::new(),
77-
));
78-
self.mk_stmt(lo.to(last_semi), kind)
65+
self.mk_stmt(lo, StmtKind::Semi(None))
7966
} else if self.token != token::CloseDelim(token::Brace) {
8067
// Remainder are line-expr stmts.
8168
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
@@ -144,12 +131,11 @@ impl<'a> Parser<'a> {
144131
/// Error on outer attributes in this context.
145132
/// Also error if the previous token was a doc comment.
146133
fn error_outer_attrs(&self, attrs: &[Attribute]) {
147-
if !attrs.is_empty() {
148-
if matches!(self.prev_token.kind, TokenKind::DocComment(..)) {
149-
self.span_fatal_err(self.prev_span, Error::UselessDocComment).emit();
134+
if let [.., last] = attrs {
135+
if last.is_doc_comment() {
136+
self.span_fatal_err(last.span, Error::UselessDocComment).emit();
150137
} else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
151-
self.struct_span_err(self.token.span, "expected statement after outer attribute")
152-
.emit();
138+
self.struct_span_err(last.span, "expected statement after outer attribute").emit();
153139
}
154140
}
155141
}
@@ -401,6 +387,7 @@ impl<'a> Parser<'a> {
401387
self.expect_semi()?;
402388
eat_semi = false;
403389
}
390+
StmtKind::Semi(None) => eat_semi = false,
404391
_ => {}
405392
}
406393

src/libsyntax/ast.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ pub struct Stmt {
879879
impl Stmt {
880880
pub fn add_trailing_semicolon(mut self) -> Self {
881881
self.kind = match self.kind {
882-
StmtKind::Expr(expr) => StmtKind::Semi(expr),
882+
StmtKind::Expr(expr) => StmtKind::Semi(Some(expr)),
883883
StmtKind::Mac(mac) => {
884884
StmtKind::Mac(mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)))
885885
}
@@ -911,8 +911,8 @@ pub enum StmtKind {
911911
Item(P<Item>),
912912
/// Expr without trailing semi-colon.
913913
Expr(P<Expr>),
914-
/// Expr with a trailing semi-colon.
915-
Semi(P<Expr>),
914+
/// Expr with a trailing semi-colon or just a trailing semi-colon.
915+
Semi(Option<P<Expr>>),
916916
/// Macro.
917917
Mac(P<(Mac, MacStmtStyle, AttrVec)>),
918918
}
@@ -1022,7 +1022,7 @@ impl Expr {
10221022
match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
10231023
// Implicit return
10241024
Some(&StmtKind::Expr(_)) => true,
1025-
Some(&StmtKind::Semi(ref expr)) => {
1025+
Some(&StmtKind::Semi(Some(ref expr))) => {
10261026
if let ExprKind::Ret(_) = expr.kind {
10271027
// Last statement is explicit return.
10281028
true

src/libsyntax/attr/mod.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -674,8 +674,8 @@ impl HasAttrs for StmtKind {
674674
fn attrs(&self) -> &[Attribute] {
675675
match *self {
676676
StmtKind::Local(ref local) => local.attrs(),
677-
StmtKind::Item(..) => &[],
678-
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
677+
StmtKind::Expr(ref expr) | StmtKind::Semi(Some(ref expr)) => expr.attrs(),
678+
StmtKind::Semi(None) | StmtKind::Item(..) => &[],
679679
StmtKind::Mac(ref mac) => {
680680
let (_, _, ref attrs) = **mac;
681681
attrs.attrs()
@@ -686,9 +686,8 @@ impl HasAttrs for StmtKind {
686686
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
687687
match self {
688688
StmtKind::Local(local) => local.visit_attrs(f),
689-
StmtKind::Item(..) => {}
690-
StmtKind::Expr(expr) => expr.visit_attrs(f),
691-
StmtKind::Semi(expr) => expr.visit_attrs(f),
689+
StmtKind::Expr(expr) | StmtKind::Semi(Some(expr)) => expr.visit_attrs(f),
690+
StmtKind::Semi(None) | StmtKind::Item(..) => {}
692691
StmtKind::Mac(mac) => {
693692
let (_mac, _style, attrs) = mac.deref_mut();
694693
attrs.visit_attrs(f);

src/libsyntax/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1264,7 +1264,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
12641264
})],
12651265
StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(),
12661266
StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(),
1267-
StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
1267+
StmtKind::Semi(e) => smallvec![StmtKind::Semi(e.and_then(|e| vis.filter_map_expr(e)))],
12681268
StmtKind::Mac(mut mac) => {
12691269
let (mac_, _semi, attrs) = mac.deref_mut();
12701270
vis.visit_mac(mac_);

src/libsyntax/visit.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -669,9 +669,8 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
669669
match statement.kind {
670670
StmtKind::Local(ref local) => visitor.visit_local(local),
671671
StmtKind::Item(ref item) => visitor.visit_item(item),
672-
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
673-
visitor.visit_expr(expression)
674-
}
672+
StmtKind::Expr(ref expr) | StmtKind::Semi(Some(ref expr)) => visitor.visit_expr(expr),
673+
StmtKind::Semi(None) => {}
675674
StmtKind::Mac(ref mac) => {
676675
let (ref mac, _, ref attrs) = **mac;
677676
visitor.visit_mac(mac);

src/test/ui/consts/const_let_eq.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ struct Bar<T> { x: T }
55
struct W(u32);
66
struct A { a: u32 }
77

8+
#[allow(redundant_semicolon)]
89
const fn basics((a,): (u32,)) -> u32 {
910
// Deferred assignment:
1011
let b: u32;

src/test/ui/consts/const_let_eq_float.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct Bar<T> { x: T }
77
struct W(f32);
88
struct A { a: f32 }
99

10+
#[allow(redundant_semicolon)]
1011
const fn basics((a,): (f32,)) -> f32 {
1112
// Deferred assignment:
1213
let b: f32;
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: expected statement after outer attribute
2-
--> $DIR/attr-dangling-in-fn.rs:5:1
2+
--> $DIR/attr-dangling-in-fn.rs:4:3
33
|
4-
LL | }
5-
| ^
4+
LL | #[foo = "bar"]
5+
| ^^^^^^^^^^^^^^
66

77
error: aborting due to previous error
88

src/test/ui/parser/attr-stmt-expr-attr-bad.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -411,16 +411,16 @@ LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
411411
| ^ expected one of `.`, `;`, `?`, or an operator
412412

413413
error: expected statement after outer attribute
414-
--> $DIR/attr-stmt-expr-attr-bad.rs:114:44
414+
--> $DIR/attr-stmt-expr-attr-bad.rs:114:37
415415
|
416416
LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
417-
| ^
417+
| ^^^^^^^
418418

419419
error: expected statement after outer attribute
420-
--> $DIR/attr-stmt-expr-attr-bad.rs:116:45
420+
--> $DIR/attr-stmt-expr-attr-bad.rs:116:37
421421
|
422422
LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } }
423-
| ^
423+
| ^^^^^^^
424424

425425
error: aborting due to 57 previous errors
426426

0 commit comments

Comments
 (0)