Skip to content

Commit c6ca96d

Browse files
committed
Auto merge of #117094 - Nadrieril:warn-lint-on-arm, r=<try>
Warn users who set `non_exhaustive_omitted_patterns` lint level on a match arm Before #116734, the recommended usage of the [`non_exhaustive_omitted_patterns` lint](#89554) was: ```rust match Bar::A { Bar::A => {}, #[warn(non_exhaustive_omitted_patterns)] _ => {}, } ``` After #116734 this no longer makes sense, and recommended usage is now: ```rust #[warn(non_exhaustive_omitted_patterns)] match Bar::A { Bar::A => {}, _ => {}, } ``` As you can guess, this silently breaks all uses of the lint that used the previous form. This is a problem in particular because `syn` recommends usage of this lint to its users in the old way. This PR emits a warning when the previous form is used so users can update. r? `@cjgillot`
2 parents 95f6a01 + d53f545 commit c6ca96d

File tree

7 files changed

+197
-24
lines changed

7 files changed

+197
-24
lines changed

Diff for: compiler/rustc_mir_build/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ mir_build_non_exhaustive_omitted_pattern = some variants are not matched explici
221221
.help = ensure that all variants are matched explicitly by adding the suggested match arms
222222
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
223223
224+
mir_build_non_exhaustive_omitted_pattern_lint_on_arm = the `non_exhaustive_omitted_pattern` lint level must be set on the whole match
225+
.help = it used to make sense to set the lint level on an individual match arm, but that is no longer the case
226+
224227
mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
225228
.def_note = `{$peeled_ty}` defined here
226229
.type_note = the matched value is of type `{$ty}`

Diff for: compiler/rustc_mir_build/src/errors.rs

+5
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,11 @@ pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
789789
pub uncovered: Uncovered<'tcx>,
790790
}
791791

792+
#[derive(LintDiagnostic)]
793+
#[diag(mir_build_non_exhaustive_omitted_pattern_lint_on_arm)]
794+
#[help]
795+
pub(crate) struct NonExhaustiveOmittedPatternLintOnArm;
796+
792797
#[derive(Subdiagnostic)]
793798
#[label(mir_build_uncovered)]
794799
pub(crate) struct Uncovered<'tcx> {

Diff for: compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

+40-23
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@
308308
use self::ArmType::*;
309309
use self::Usefulness::*;
310310
use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, WitnessPat};
311-
use crate::errors::{NonExhaustiveOmittedPattern, Uncovered};
311+
use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered};
312312

313313
use rustc_data_structures::captures::Captures;
314314

@@ -1024,30 +1024,47 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
10241024

10251025
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
10261026
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
1027-
if cx.refutable
1028-
&& non_exhaustiveness_witnesses.is_empty()
1029-
&& !matches!(
1027+
if cx.refutable && non_exhaustiveness_witnesses.is_empty() {
1028+
if !matches!(
10301029
cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0,
10311030
rustc_session::lint::Level::Allow
1032-
)
1033-
{
1034-
let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>();
1035-
let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column);
1036-
1037-
if !witnesses.is_empty() {
1038-
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
1039-
// is not exhaustive enough.
1040-
//
1041-
// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
1042-
cx.tcx.emit_spanned_lint(
1043-
NON_EXHAUSTIVE_OMITTED_PATTERNS,
1044-
lint_root,
1045-
scrut_span,
1046-
NonExhaustiveOmittedPattern {
1047-
scrut_ty,
1048-
uncovered: Uncovered::new(scrut_span, cx, witnesses),
1049-
},
1050-
);
1031+
) {
1032+
let pat_column =
1033+
arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>();
1034+
let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column);
1035+
1036+
if !witnesses.is_empty() {
1037+
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
1038+
// is not exhaustive enough.
1039+
//
1040+
// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
1041+
cx.tcx.emit_spanned_lint(
1042+
NON_EXHAUSTIVE_OMITTED_PATTERNS,
1043+
lint_root,
1044+
scrut_span,
1045+
NonExhaustiveOmittedPattern {
1046+
scrut_ty,
1047+
uncovered: Uncovered::new(scrut_span, cx, witnesses),
1048+
},
1049+
);
1050+
}
1051+
} else {
1052+
// We used to allow putting the `#[allow(non_exhaustive_omitted_patterns)]` on a match
1053+
// arm. This no longer makes sense so we warn users, to avoid silently breaking their
1054+
// usage of the lint.
1055+
for arm in arms {
1056+
if !matches!(
1057+
cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.hir_id).0,
1058+
rustc_session::lint::Level::Allow
1059+
) {
1060+
cx.tcx.emit_spanned_lint(
1061+
NON_EXHAUSTIVE_OMITTED_PATTERNS,
1062+
arm.hir_id,
1063+
arm.pat.span(),
1064+
NonExhaustiveOmittedPatternLintOnArm,
1065+
);
1066+
}
1067+
}
10511068
}
10521069
}
10531070

Diff for: src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ fn repeat() -> ! {
99
}
1010

1111
pub fn f(x: Ordering) {
12+
#[deny(non_exhaustive_omitted_patterns)]
1213
match x {
1314
Ordering::Relaxed => println!("relaxed"),
1415
Ordering::Release => println!("release"),
1516
Ordering::Acquire => println!("acquire"),
1617
Ordering::AcqRel | Ordering::SeqCst => repeat(),
17-
#[deny(non_exhaustive_omitted_patterns)]
1818
_ => repeat(),
1919
}
2020
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error: some variants are not matched explicitly
2+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:15:11
3+
|
4+
LL | match val {
5+
| ^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
6+
|
7+
= help: ensure that all variants are matched explicitly by adding the suggested match arms
8+
= note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
9+
note: the lint level is defined here
10+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:14:12
11+
|
12+
LL | #[deny(non_exhaustive_omitted_patterns)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: some variants are not matched explicitly
16+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:23:11
17+
|
18+
LL | match val {
19+
| ^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
20+
|
21+
= help: ensure that all variants are matched explicitly by adding the suggested match arms
22+
= note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
23+
note: the lint level is defined here
24+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:22:27
25+
|
26+
LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))]
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
29+
error: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match
30+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:34:9
31+
|
32+
LL | _ => {}
33+
| ^
34+
|
35+
= help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case
36+
note: the lint level is defined here
37+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:33:16
38+
|
39+
LL | #[deny(non_exhaustive_omitted_patterns)]
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
42+
error: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match
43+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:41:9
44+
|
45+
LL | _ => {}
46+
| ^
47+
|
48+
= help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case
49+
note: the lint level is defined here
50+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:40:31
51+
|
52+
LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))]
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54+
55+
warning: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match
56+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:48:9
57+
|
58+
LL | _ => {}
59+
| ^
60+
|
61+
= help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case
62+
note: the lint level is defined here
63+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:47:31
64+
|
65+
LL | #[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))]
66+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67+
68+
error: aborting due to 4 previous errors; 1 warning emitted
69+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: some variants are not matched explicitly
2+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:15:11
3+
|
4+
LL | match val {
5+
| ^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
6+
|
7+
= help: ensure that all variants are matched explicitly by adding the suggested match arms
8+
= note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
9+
note: the lint level is defined here
10+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:14:12
11+
|
12+
LL | #[deny(non_exhaustive_omitted_patterns)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match
16+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:34:9
17+
|
18+
LL | _ => {}
19+
| ^
20+
|
21+
= help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case
22+
note: the lint level is defined here
23+
--> $DIR/omitted-patterns-dont-lint-on-arm.rs:33:16
24+
|
25+
LL | #[deny(non_exhaustive_omitted_patterns)]
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
28+
error: aborting due to 2 previous errors
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// revisions: normal lint
2+
// Test that putting the lint level on a match arm emits a warning, as this was previously
3+
// meaningful and is no longer.
4+
#![feature(non_exhaustive_omitted_patterns_lint)]
5+
6+
// aux-build:enums.rs
7+
extern crate enums;
8+
9+
use enums::NonExhaustiveEnum;
10+
11+
fn main() {
12+
let val = NonExhaustiveEnum::Unit;
13+
14+
#[deny(non_exhaustive_omitted_patterns)]
15+
match val {
16+
//~^ ERROR some variants are not matched explicitly
17+
NonExhaustiveEnum::Unit => {}
18+
NonExhaustiveEnum::Tuple(_) => {}
19+
_ => {}
20+
}
21+
22+
#[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))]
23+
match val {
24+
//[lint]~^ ERROR some variants are not matched explicitly
25+
NonExhaustiveEnum::Unit => {}
26+
NonExhaustiveEnum::Tuple(_) => {}
27+
_ => {}
28+
}
29+
30+
match val {
31+
NonExhaustiveEnum::Unit => {}
32+
NonExhaustiveEnum::Tuple(_) => {}
33+
#[deny(non_exhaustive_omitted_patterns)]
34+
_ => {} //~ ERROR lint level must be set on the whole match
35+
}
36+
37+
match val {
38+
NonExhaustiveEnum::Unit => {}
39+
NonExhaustiveEnum::Tuple(_) => {}
40+
#[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))]
41+
_ => {} //[lint]~ ERROR lint level must be set on the whole match
42+
}
43+
44+
match val {
45+
NonExhaustiveEnum::Unit => {}
46+
NonExhaustiveEnum::Tuple(_) => {}
47+
#[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))]
48+
_ => {} //[lint]~ WARN lint level must be set on the whole match
49+
}
50+
}

0 commit comments

Comments
 (0)