diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 162cfce0a24..9f10dc4b634 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -313,10 +313,10 @@ mir_build_float_pattern = floating-point types cannot be used in patterns mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. -mir_build_indirect_structural_match = +mir_build_indirect_structural_match = to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` -mir_build_nontrivial_structural_match = +mir_build_nontrivial_structural_match = to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints @@ -324,3 +324,13 @@ mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpo .note = you likely meant to write mutually exclusive ranges mir_build_overlapping_range = this range overlaps on `{$range}`... + +mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly + .label = {$count -> + [1] pattern `{$witness_1}` + [2] patterns `{$witness_1}` and `{$witness_2}` + [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` + *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and more + } not covered + .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 diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 6bb15730b00..e15da5bb9ce 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -685,3 +685,17 @@ pub struct Overlap<'tcx> { pub span: Span, pub range: Pat<'tcx>, } + +#[derive(LintDiagnostic)] +#[diag(mir_build_non_exhaustive_omitted_pattern)] +#[help] +#[note] +pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { + pub scrut_ty: Ty<'tcx>, + #[label] + pub uncovered: Span, + pub count: usize, + pub witness_1: Pat<'tcx>, + pub witness_2: Pat<'tcx>, + pub witness_3: Pat<'tcx>, +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 8e7ca32feb3..7f3519945c3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -435,7 +435,7 @@ impl<'tcx> ConstToPat<'tcx> { _ => { if !pointee_ty.is_sized(tcx, param_env) { // `tcx.deref_mir_constant()` below will ICE with an unsized type - // (except slices, which are handled in a separate arm above). + // (except slices, which are handled in a separate arm above). let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 2c775b39718..6395b75a08f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -2,7 +2,7 @@ mod check_match; mod const_to_pat; -mod deconstruct_pat; +pub(crate) mod deconstruct_pat; mod usefulness; pub(crate) use self::check_match::check_match; diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 8f80cb95e58..37aed5bd14d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -291,9 +291,8 @@ use self::ArmType::*; use self::Usefulness::*; - -use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label}; use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; +use crate::errors::NonExhaustiveOmittedPattern; use rustc_data_structures::captures::Captures; @@ -754,6 +753,23 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( hir_id: HirId, witnesses: Vec>, ) { + let witness_1 = witnesses.get(0).unwrap().to_pat(cx); + + cx.tcx.emit_spanned_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + hir_id, + sp, + NonExhaustiveOmittedPattern { + scrut_ty, + uncovered: sp, + count: witnesses.len(), + // Substitute dummy values if witnesses is smaller than 3. + witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()), + witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()), + witness_1, + }, + ); + /* cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| { let joined_patterns = joined_uncovered_patterns(cx, &witnesses); lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); @@ -766,6 +782,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( )); lint }); + */ } /// Algorithm from .