diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index c74b399555a8a..aa7c87e9f7bd2 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -355,6 +355,19 @@ impl From for &'static str { trait UnusedDelimLint { const DELIM_STR: &'static str; + /// Due to `ref` pattern, there can be a difference between using + /// `{ expr }` and `expr` in pattern-matching contexts. This means + /// that we should only lint `unused_parens` and not `unused_braces` + /// in this case. + /// + /// ```rust + /// let mut a = 7; + /// let ref b = { a }; // We actually borrow a copy of `a` here. + /// a += 1; // By mutating `a` we invalidate any borrows of `a`. + /// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here. + /// ``` + const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool; + // this cannot be a constant is it refers to a static. fn lint(&self) -> &'static Lint; @@ -454,7 +467,10 @@ trait UnusedDelimLint { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use rustc_ast::ast::ExprKind::*; let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind { - If(ref cond, ref block, ..) => { + // Do not lint `unused_braces` in `if let` expressions. + If(ref cond, ref block, ..) + if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => + { let left = e.span.lo() + rustc_span::BytePos(2); let right = block.span.lo(); (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right)) @@ -470,7 +486,7 @@ trait UnusedDelimLint { (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo())) } - Match(ref head, _) => { + Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { let left = e.span.lo() + rustc_span::BytePos(5); (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None) } @@ -512,7 +528,7 @@ trait UnusedDelimLint { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { match s.kind { - StmtKind::Local(ref local) => { + StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { if let Some(ref value) = local.init { self.check_unused_delims_expr( cx, @@ -565,6 +581,8 @@ declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedDelimLint for UnusedParens { const DELIM_STR: &'static str = "parentheses"; + const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true; + fn lint(&self) -> &'static Lint { UNUSED_PARENS } @@ -736,6 +754,8 @@ declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]); impl UnusedDelimLint for UnusedBraces { const DELIM_STR: &'static str = "braces"; + const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false; + fn lint(&self) -> &'static Lint { UNUSED_BRACES } diff --git a/src/test/ui/lint/unused_braces.rs b/src/test/ui/lint/unused_braces.rs index de456ee6c230c..952398ef0685b 100644 --- a/src/test/ui/lint/unused_braces.rs +++ b/src/test/ui/lint/unused_braces.rs @@ -1,29 +1,48 @@ // check-pass #![warn(unused_braces, unused_parens)] +fn consume(_: T) {} + fn main() { let _ = (7); //~^WARN unnecessary parentheses - let _ = { 7 }; - //~^ WARN unnecessary braces + // Do not emit a lint in these cases, + // as we have to be careful with + // `ref` patterns. + { + let _ = { 7 }; + + if let 7 = { 7 } { } + + match { 7 } { + _ => (), + } + } - if let 7 = { 7 } { + if { true } { + //~^ WARN unnecessary braces + } + + while { false } { //~^ WARN unnecessary braces } let _: [u8; { 3 }]; //~^ WARN unnecessary braces - // do not emit error for multiline blocks. + consume({ 7 }); + //~^ WARN unnecessary braces + + // Do not emit lint for multiline blocks. let _ = { 7 }; - // do not emit error for unsafe blocks. + // Do not emit lint for unsafe blocks. let _ = unsafe { 7 }; - // do not emit error, as the `{` would then + // Do not emit lint, as the `{` would then // be parsed as part of the `return`. if { return } { diff --git a/src/test/ui/lint/unused_braces.stderr b/src/test/ui/lint/unused_braces.stderr index 72f425ffc3e01..f195c00241836 100644 --- a/src/test/ui/lint/unused_braces.stderr +++ b/src/test/ui/lint/unused_braces.stderr @@ -1,5 +1,5 @@ warning: unnecessary parentheses around assigned value - --> $DIR/unused_braces.rs:5:13 + --> $DIR/unused_braces.rs:7:13 | LL | let _ = (7); | ^^^ help: remove these parentheses @@ -10,11 +10,11 @@ note: the lint level is defined here LL | #![warn(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ -warning: unnecessary braces around assigned value - --> $DIR/unused_braces.rs:8:13 +warning: unnecessary braces around `if` condition + --> $DIR/unused_braces.rs:23:8 | -LL | let _ = { 7 }; - | ^^^^^ help: remove these braces +LL | if { true } { + | ^^^^^^^^ help: remove these braces | note: the lint level is defined here --> $DIR/unused_braces.rs:2:9 @@ -22,15 +22,21 @@ note: the lint level is defined here LL | #![warn(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ -warning: unnecessary braces around `let` scrutinee expression - --> $DIR/unused_braces.rs:11:16 +warning: unnecessary braces around `while` condition + --> $DIR/unused_braces.rs:27:11 | -LL | if let 7 = { 7 } { - | ^^^^^ help: remove these braces +LL | while { false } { + | ^^^^^^^^^ help: remove these braces warning: unnecessary braces around const expression - --> $DIR/unused_braces.rs:15:17 + --> $DIR/unused_braces.rs:31:17 | LL | let _: [u8; { 3 }]; | ^^^^^ help: remove these braces +warning: unnecessary braces around function argument + --> $DIR/unused_braces.rs:34:13 + | +LL | consume({ 7 }); + | ^^^^^ help: remove these braces + diff --git a/src/test/ui/lint/unused_parens_borrow.rs b/src/test/ui/lint/unused_braces_borrow.rs similarity index 81% rename from src/test/ui/lint/unused_parens_borrow.rs rename to src/test/ui/lint/unused_braces_borrow.rs index 98dbbecfedde6..d0b059744e1fd 100644 --- a/src/test/ui/lint/unused_parens_borrow.rs +++ b/src/test/ui/lint/unused_braces_borrow.rs @@ -10,13 +10,15 @@ struct A { b: u32, } +fn consume(_: T) {} + fn main() { let a = A { a: 42, b: 1729, }; - let _ = &{ a.b }; - let _ = { a.b }; + consume(&{ a.b }); + consume({ a.b }); //~^ WARN unnecessary braces } diff --git a/src/test/ui/lint/unused_parens_borrow.stderr b/src/test/ui/lint/unused_braces_borrow.stderr similarity index 50% rename from src/test/ui/lint/unused_parens_borrow.stderr rename to src/test/ui/lint/unused_braces_borrow.stderr index 7e3839ae4e014..82fb4375611c9 100644 --- a/src/test/ui/lint/unused_parens_borrow.stderr +++ b/src/test/ui/lint/unused_braces_borrow.stderr @@ -1,11 +1,11 @@ -warning: unnecessary braces around assigned value - --> $DIR/unused_parens_borrow.rs:20:13 +warning: unnecessary braces around function argument + --> $DIR/unused_braces_borrow.rs:22:13 | -LL | let _ = { a.b }; +LL | consume({ a.b }); | ^^^^^^^ help: remove these braces | note: the lint level is defined here - --> $DIR/unused_parens_borrow.rs:2:9 + --> $DIR/unused_braces_borrow.rs:2:9 | LL | #![warn(unused_braces)] | ^^^^^^^^^^^^^