Skip to content

Commit 3a03587

Browse files
committed
Consider lint check attributes on match arms in match checks
1 parent ddafe23 commit 3a03587

File tree

3 files changed

+88
-23
lines changed

3 files changed

+88
-23
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+35-23
Original file line numberDiff line numberDiff line change
@@ -90,35 +90,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
9090

9191
#[instrument(level = "trace", skip(self))]
9292
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
93-
match arm.guard {
94-
Some(Guard::If(expr)) => {
95-
self.with_let_source(LetSource::IfLetGuard, |this| {
96-
this.visit_expr(&this.thir[expr])
97-
});
98-
}
99-
Some(Guard::IfLet(ref pat, expr)) => {
100-
self.with_let_source(LetSource::IfLetGuard, |this| {
101-
this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
102-
this.visit_pat(pat);
103-
this.visit_expr(&this.thir[expr]);
104-
});
93+
self.with_lint_level(arm.lint_level, |this| {
94+
match arm.guard {
95+
Some(Guard::If(expr)) => {
96+
this.with_let_source(LetSource::IfLetGuard, |this| {
97+
this.visit_expr(&this.thir[expr])
98+
});
99+
}
100+
Some(Guard::IfLet(ref pat, expr)) => {
101+
this.with_let_source(LetSource::IfLetGuard, |this| {
102+
this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
103+
this.visit_pat(pat);
104+
this.visit_expr(&this.thir[expr]);
105+
});
106+
}
107+
None => {}
105108
}
106-
None => {}
107-
}
108-
self.visit_pat(&arm.pattern);
109-
self.visit_expr(&self.thir[arm.body]);
109+
this.visit_pat(&arm.pattern);
110+
this.visit_expr(&self.thir[arm.body]);
111+
});
110112
}
111113

112114
#[instrument(level = "trace", skip(self))]
113115
fn visit_expr(&mut self, ex: &Expr<'tcx>) {
114116
match ex.kind {
115117
ExprKind::Scope { value, lint_level, .. } => {
116-
let old_lint_level = self.lint_level;
117-
if let LintLevel::Explicit(hir_id) = lint_level {
118-
self.lint_level = hir_id;
119-
}
120-
self.visit_expr(&self.thir[value]);
121-
self.lint_level = old_lint_level;
118+
self.with_lint_level(lint_level, |this| {
119+
this.visit_expr(&this.thir[value]);
120+
});
122121
return;
123122
}
124123
ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
@@ -190,6 +189,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
190189
self.let_source = old_let_source;
191190
}
192191

192+
fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
193+
if let LintLevel::Explicit(hir_id) = new_lint_level {
194+
let old_lint_level = self.lint_level;
195+
self.lint_level = hir_id;
196+
f(self);
197+
self.lint_level = old_lint_level;
198+
} else {
199+
f(self);
200+
}
201+
}
202+
193203
fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
194204
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
195205
check_for_bindings_named_same_as_variants(self, pat, rf);
@@ -236,7 +246,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
236246
for &arm in arms {
237247
// Check the arm for some things unrelated to exhaustiveness.
238248
let arm = &self.thir.arms[arm];
239-
self.check_patterns(&arm.pattern, Refutable);
249+
self.with_lint_level(arm.lint_level, |this| {
250+
this.check_patterns(&arm.pattern, Refutable);
251+
});
240252
}
241253

242254
let tarms: Vec<_> = arms

tests/ui/lint/lint-match-arms-2.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(if_let_guard)]
2+
#![allow(unused, non_snake_case)]
3+
4+
enum E {
5+
A,
6+
}
7+
8+
#[allow(bindings_with_variant_name, irrefutable_let_patterns)]
9+
fn foo() {
10+
match E::A {
11+
#[deny(bindings_with_variant_name)]
12+
A => {}
13+
//~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E`
14+
}
15+
16+
match &E::A {
17+
#[deny(irrefutable_let_patterns)]
18+
a if let b = a => {}
19+
//~^ ERROR irrefutable `if let` guard pattern
20+
_ => {}
21+
}
22+
}
23+
24+
fn main() { }
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
2+
--> $DIR/lint-match-arms-2.rs:12:9
3+
|
4+
LL | A => {}
5+
| ^ help: to match on the variant, qualify the path: `E::A`
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/lint-match-arms-2.rs:11:16
9+
|
10+
LL | #[deny(bindings_with_variant_name)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: irrefutable `if let` guard pattern
14+
--> $DIR/lint-match-arms-2.rs:18:18
15+
|
16+
LL | a if let b = a => {}
17+
| ^
18+
|
19+
= note: this pattern will always match, so the guard is useless
20+
= help: consider removing the guard and adding a `let` inside the match arm
21+
note: the lint level is defined here
22+
--> $DIR/lint-match-arms-2.rs:17:16
23+
|
24+
LL | #[deny(irrefutable_let_patterns)]
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0170`.

0 commit comments

Comments
 (0)