diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index ed16d41a74334..563851f712c66 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -221,8 +221,10 @@ mir_build_non_exhaustive_omitted_pattern = some variants are not matched explici .help = ensure that all variants are matched explicitly by adding the suggested match arms .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found -mir_build_non_exhaustive_omitted_pattern_lint_on_arm = the `non_exhaustive_omitted_pattern` lint level must be set on the whole match - .help = it used to make sense to set the lint level on an individual match arm, but that is no longer the case +mir_build_non_exhaustive_omitted_pattern_lint_on_arm = the lint level must be set on the whole match + .help = it no longer has any effect to set the lint level on an individual match arm + .label = remove this attribute + .suggestion = set the lint level on the whole match mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty .def_note = `{$peeled_ty}` defined here diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 378a957df0fb9..c4eed5532ee63 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -792,7 +792,14 @@ pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { #[derive(LintDiagnostic)] #[diag(mir_build_non_exhaustive_omitted_pattern_lint_on_arm)] #[help] -pub(crate) struct NonExhaustiveOmittedPatternLintOnArm; +pub(crate) struct NonExhaustiveOmittedPatternLintOnArm { + #[label] + pub lint_span: Span, + #[suggestion(code = "#[{lint_level}({lint_name})]\n", applicability = "maybe-incorrect")] + pub suggest_lint_on_match: Option, + pub lint_level: &'static str, + pub lint_name: &'static str, +} #[derive(Subdiagnostic)] #[label(mir_build_uncovered)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 933653e708e94..72aaebcbd63e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -218,12 +218,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) } - fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> { + fn new_cx( + &self, + hir_id: HirId, + refutable: bool, + match_span: Option, + ) -> MatchCheckCtxt<'p, 'tcx> { MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, module: self.tcx.parent_module(hir_id).to_def_id(), pattern_arena: &self.pattern_arena, + match_span, refutable, } } @@ -238,7 +244,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } self.check_patterns(pat, Refutable); - let mut cx = self.new_cx(self.lint_level, true); + let mut cx = self.new_cx(self.lint_level, true, None); let tpat = self.lower_pattern(&mut cx, pat); self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); } @@ -250,7 +256,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { source: hir::MatchSource, expr_span: Span, ) { - let mut cx = self.new_cx(self.lint_level, true); + let mut cx = self.new_cx(self.lint_level, true, Some(expr_span)); for &arm in arms { // Check the arm for some things unrelated to exhaustiveness. @@ -363,7 +369,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { error = Err(err); return None; } - let mut ncx = self.new_cx(local_lint_level, true); + let mut ncx = self.new_cx(local_lint_level, true, None); let tpat = self.lower_pattern(&mut ncx, pat); let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); Some((expr.span, refutable)) @@ -468,7 +474,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } - let mut cx = self.new_cx(self.lint_level, false); + let mut cx = self.new_cx(self.lint_level, false, None); let pattern = self.lower_pattern(&mut cx, pat); let pattern_ty = pattern.ty(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 233b911bfee11..da7b6587a7220 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -340,6 +340,8 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> { pub(crate) module: DefId, pub(crate) param_env: ty::ParamEnv<'tcx>, pub(crate) pattern_arena: &'p TypedArena>, + /// The span of the whole match, if applicable. + pub(crate) match_span: Option, /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns. pub(crate) refutable: bool, } @@ -1179,16 +1181,21 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( // arm. This no longer makes sense so we warn users, to avoid silently breaking their // usage of the lint. for arm in arms { - if !matches!( - cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.hir_id).0, - rustc_session::lint::Level::Allow - ) { - cx.tcx.emit_spanned_lint( - NON_EXHAUSTIVE_OMITTED_PATTERNS, - arm.hir_id, - arm.pat.span(), - NonExhaustiveOmittedPatternLintOnArm, - ); + let (lint_level, lint_level_source) = + cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.hir_id); + if !matches!(lint_level, rustc_session::lint::Level::Allow) { + let decorator = NonExhaustiveOmittedPatternLintOnArm { + lint_span: lint_level_source.span(), + suggest_lint_on_match: cx.match_span.map(|span| span.shrink_to_lo()), + lint_level: lint_level.as_str(), + lint_name: "non_exhaustive_omitted_patterns", + }; + + use rustc_errors::DecorateLint; + let mut err = cx.tcx.sess.struct_span_warn(arm.pat.span(), ""); + err.set_primary_message(decorator.msg()); + decorator.decorate_lint(&mut err); + err.emit(); } } } diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr index b0629c6de1a48..9192c66143cc4 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr @@ -26,44 +26,50 @@ note: the lint level is defined here LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match +warning: the lint level must be set on the whole match --> $DIR/omitted-patterns-dont-lint-on-arm.rs:34:9 | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ------------------------------- remove this attribute LL | _ => {} | ^ | - = help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case -note: the lint level is defined here - --> $DIR/omitted-patterns-dont-lint-on-arm.rs:33:16 + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[deny(non_exhaustive_omitted_patterns)] +LL | match val { | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match - --> $DIR/omitted-patterns-dont-lint-on-arm.rs:41:9 +warning: the lint level must be set on the whole match + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:42:9 | +LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] + | ------------------------------- remove this attribute LL | _ => {} | ^ | - = help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case -note: the lint level is defined here - --> $DIR/omitted-patterns-dont-lint-on-arm.rs:40:31 + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[deny(non_exhaustive_omitted_patterns)] +LL | match val { | -LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match - --> $DIR/omitted-patterns-dont-lint-on-arm.rs:48:9 +warning: the lint level must be set on the whole match + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:50:9 | +LL | #[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))] + | ------------------------------- remove this attribute LL | _ => {} | ^ | - = help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case -note: the lint level is defined here - --> $DIR/omitted-patterns-dont-lint-on-arm.rs:47:31 + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[warn(non_exhaustive_omitted_patterns)] +LL | match val { | -LL | #[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 3 warnings emitted diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr index a7a2ad3a5f0d3..46093eb9fb35f 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr @@ -12,18 +12,20 @@ note: the lint level is defined here LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the `non_exhaustive_omitted_pattern` lint level must be set on the whole match +warning: the lint level must be set on the whole match --> $DIR/omitted-patterns-dont-lint-on-arm.rs:34:9 | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ------------------------------- remove this attribute LL | _ => {} | ^ | - = help: it used to make sense to set the lint level on an individual match arm, but that is no longer the case -note: the lint level is defined here - --> $DIR/omitted-patterns-dont-lint-on-arm.rs:33:16 + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[deny(non_exhaustive_omitted_patterns)] +LL | match val { | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs index ac7b7cd93fd1f..33f9f56a5bbc8 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs @@ -31,20 +31,23 @@ fn main() { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} #[deny(non_exhaustive_omitted_patterns)] - _ => {} //~ ERROR lint level must be set on the whole match + _ => {} } + //~^^ WARN lint level must be set on the whole match match val { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] - _ => {} //[lint]~ ERROR lint level must be set on the whole match + _ => {} } + //[lint]~^^ WARN lint level must be set on the whole match match val { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} #[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))] - _ => {} //[lint]~ WARN lint level must be set on the whole match + _ => {} } + //[lint]~^^ WARN lint level must be set on the whole match }