Skip to content

Commit 012f029

Browse files
committed
Fix unused_braces linting
1 parent 3e887f5 commit 012f029

File tree

5 files changed

+130
-2
lines changed

5 files changed

+130
-2
lines changed

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ early_lint_methods!(
166166
pub BuiltinCombinedEarlyLintPass,
167167
[
168168
UnusedParens: UnusedParens::default(),
169-
UnusedBraces: UnusedBraces,
169+
UnusedBraces: UnusedBraces::default(),
170170
UnusedImportBraces: UnusedImportBraces,
171171
UnsafeCode: UnsafeCode,
172172
SpecialModuleName: SpecialModuleName,

compiler/rustc_lint/src/unused.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,25 @@ trait UnusedDelimLint {
656656
is_kw: bool,
657657
);
658658

659+
#[inline]
660+
fn impacts_followed_by_block(e: &ast::Expr) -> bool {
661+
return match e.kind {
662+
ExprKind::Block(..) | ExprKind::Call(..) | ExprKind::MethodCall(..) => true,
663+
_ => Self::is_followed_by_block(e),
664+
};
665+
}
666+
667+
#[inline]
668+
fn is_followed_by_block(e: &ast::Expr) -> bool {
669+
return match e.kind {
670+
ExprKind::If(ref cond, ..) if !matches!(cond.kind, ExprKind::Let(..)) => true,
671+
ExprKind::While(ref cond, ..) if !matches!(cond.kind, ExprKind::Let(..)) => true,
672+
ExprKind::ForLoop { .. } => true,
673+
ExprKind::Match(_, _, ast::MatchKind::Prefix) => true,
674+
_ => false,
675+
};
676+
}
677+
659678
fn is_expr_delims_necessary(
660679
inner: &ast::Expr,
661680
ctx: UnusedDelimsCtx,
@@ -1475,7 +1494,15 @@ declare_lint! {
14751494
"unnecessary braces around an expression"
14761495
}
14771496

1478-
declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
1497+
#[derive(Default)]
1498+
pub(crate) struct UnusedBraces {
1499+
// Used for tracking parent expressions that would immediately followed
1500+
// by block. Storing false here indicates that expression itself is Block
1501+
// expression. This is meant for to prevent report false positive cases.
1502+
followed_by_block: Vec<bool>,
1503+
}
1504+
1505+
impl_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
14791506

14801507
impl UnusedDelimLint for UnusedBraces {
14811508
const DELIM_STR: &'static str = "braces";
@@ -1505,6 +1532,11 @@ impl UnusedDelimLint for UnusedBraces {
15051532
// - the block does not have a label
15061533
// - the block is not `unsafe`
15071534
// - the block contains exactly one expression (do not lint `{ expr; }`)
1535+
// - however, this does not lint if block is immediately followed by parent
1536+
// expression's block, e.g. `if` and `match`, which may cause false positive.
1537+
// ```
1538+
// if return { return } {} else {}
1539+
// ```
15081540
// - `followed_by_block` is true and the internal expr may contain a `{`
15091541
// - the block is not multiline (do not lint multiline match arms)
15101542
// ```
@@ -1524,9 +1556,18 @@ impl UnusedDelimLint for UnusedBraces {
15241556
// let _: A<{produces_literal!()}>;
15251557
// ```
15261558
// FIXME(const_generics): handle paths when #67075 is fixed.
1559+
// if ctx == UnusedDelimsCtx::FunctionArg {
1560+
// println!("{:?}", self.followed_by_block.last().copied().unwrap_or(false))
1561+
// }
15271562
if let [stmt] = inner.stmts.as_slice()
15281563
&& let ast::StmtKind::Expr(ref expr) = stmt.kind
15291564
&& !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
1565+
&& ((ctx == UnusedDelimsCtx::FunctionArg || ctx == UnusedDelimsCtx::MethodArg)
1566+
|| !Self::is_expr_delims_necessary(
1567+
expr,
1568+
ctx,
1569+
self.followed_by_block.last().copied().unwrap_or(false),
1570+
))
15301571
&& (ctx != UnusedDelimsCtx::AnonConst
15311572
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
15321573
&& !expr.span.from_expansion()))
@@ -1564,6 +1605,10 @@ impl EarlyLintPass for UnusedBraces {
15641605
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
15651606
<Self as UnusedDelimLint>::check_expr(self, cx, e);
15661607

1608+
if <Self as UnusedDelimLint>::impacts_followed_by_block(e) {
1609+
self.followed_by_block.push(<Self as UnusedDelimLint>::is_followed_by_block(e));
1610+
}
1611+
15671612
if let ExprKind::Repeat(_, ref anon_const) = e.kind {
15681613
self.check_unused_delims_expr(
15691614
cx,
@@ -1577,6 +1622,18 @@ impl EarlyLintPass for UnusedBraces {
15771622
}
15781623
}
15791624

1625+
fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) {
1626+
if <Self as UnusedDelimLint>::impacts_followed_by_block(e) {
1627+
let followed_by_block =
1628+
self.followed_by_block.pop().expect("check_expr and check_expr_post must balance");
1629+
assert_eq!(
1630+
followed_by_block,
1631+
Self::is_followed_by_block(e),
1632+
"check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"
1633+
);
1634+
}
1635+
}
1636+
15801637
fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
15811638
if let ast::GenericArg::Const(ct) = arg {
15821639
self.check_unused_delims_expr(
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ run-rustfix
2+
//@ check-pass
3+
#[allow(unreachable_code)]
4+
#[allow(unused)]
5+
#[warn(unused_braces)]
6+
#[warn(unused_parens)]
7+
8+
fn main() {
9+
return return; //~ WARN: unnecessary braces
10+
if f(return) {} else {} //~ WARN: unnecessary braces
11+
if return { return } { return } else { return }
12+
match return { return } {
13+
_ => { return }
14+
}
15+
while return { return } {}
16+
}
17+
18+
fn f(_a: ()) -> bool {
19+
true
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ run-rustfix
2+
//@ check-pass
3+
#[allow(unreachable_code)]
4+
#[allow(unused)]
5+
#[warn(unused_braces)]
6+
#[warn(unused_parens)]
7+
8+
fn main() {
9+
return { return }; //~ WARN: unnecessary braces
10+
if f({ return }) {} else {} //~ WARN: unnecessary braces
11+
if return { return } { return } else { return }
12+
match return { return } {
13+
_ => { return }
14+
}
15+
while return { return } {}
16+
}
17+
18+
fn f(_a: ()) -> bool {
19+
true
20+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
warning: unnecessary braces around `return` value
2+
--> $DIR/unused-braces-respect-parent-block-issue-141783.rs:9:12
3+
|
4+
LL | return { return };
5+
| ^^ ^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/unused-braces-respect-parent-block-issue-141783.rs:5:8
9+
|
10+
LL | #[warn(unused_braces)]
11+
| ^^^^^^^^^^^^^
12+
help: remove these braces
13+
|
14+
LL - return { return };
15+
LL + return return;
16+
|
17+
18+
warning: unnecessary braces around function argument
19+
--> $DIR/unused-braces-respect-parent-block-issue-141783.rs:10:10
20+
|
21+
LL | if f({ return }) {} else {}
22+
| ^^ ^^
23+
|
24+
help: remove these braces
25+
|
26+
LL - if f({ return }) {} else {}
27+
LL + if f(return) {} else {}
28+
|
29+
30+
warning: 2 warnings emitted
31+

0 commit comments

Comments
 (0)