diff --git a/compiler/rustc_mir_build/src/diagnostics.rs b/compiler/rustc_mir_build/src/diagnostics.rs index 40d9b0990b2fc..86418f0a9a947 100644 --- a/compiler/rustc_mir_build/src/diagnostics.rs +++ b/compiler/rustc_mir_build/src/diagnostics.rs @@ -775,6 +775,10 @@ pub(crate) struct UnreachablePatternInner<'tcx> { pub(crate) covered_by_many: Option, #[suggestion("remove the match arm", code = "", applicability = "machine-applicable")] pub(crate) suggest_remove: Option, + #[note( + "`#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate" + )] + pub(crate) non_exhaustive_attr: Option, } #[derive(Subdiagnostic)] 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 d597feb33d9fd..dce980a7cf89c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,5 +1,6 @@ use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::Mutability; +use rustc_attr_ir::find_attr; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, msg, struct_span_code_err}; @@ -982,6 +983,7 @@ fn report_unreachable_pattern<'p, 'tcx>( inaccessible_constant: None, pattern_let_binding: None, suggest_remove: None, + non_exhaustive_attr: None, }; let mut covered_by_many_n_more_count = None; match explanation.covered_by.as_slice() { @@ -1031,6 +1033,16 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.covered_by_many = Some(multispan); } } + + if let Constructor::Wildcard = pat.ctor() + && let ty::Adt(adt, _) = pat.ty().peel_refs().kind() + && adt.is_enum() + && let Some(did) = adt.did().as_local() + && let Some(span) = find_attr!(cx.tcx, did, NonExhaustive(span) => span) + { + lint.non_exhaustive_attr = Some(*span); + } + cx.tcx.emit_node_span_lint( UNREACHABLE_PATTERNS, hir_id, diff --git a/tests/ui/match/unreachable-pattern-with-non-exhaustive.rs b/tests/ui/match/unreachable-pattern-with-non-exhaustive.rs new file mode 100644 index 0000000000000..940b096dda48f --- /dev/null +++ b/tests/ui/match/unreachable-pattern-with-non-exhaustive.rs @@ -0,0 +1,53 @@ +//@ aux-crate:upstream=match_non_exhaustive_lib.rs +//@ dont-require-annotations: NOTE +//@ edition: 2024 + +#![deny(unreachable_patterns)] + +#[non_exhaustive] +//~^ NOTE `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate +//~| NOTE `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate +//~| NOTE `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate +//~| NOTE `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate +enum E1 { A, B } + +fn foo(e: E1) { + match e { + E1::A | E1::B => {} + _ => {} + //~^ ERROR unreachable pattern + } +} + +fn foo_ref(e: &E1) { + match e { + E1::A | E1::B => {} + _ => {} + //~^ ERROR unreachable pattern + } +} + +fn foo_mut_ref(e: &mut E1) { + match e { + E1::A | E1::B => {} + _ => {} + //~^ ERROR unreachable pattern + } +} + +fn bar(e: Option) { + match e { + Some(E1::A | E1::B | _) => {} + //~^ ERROR unreachable pattern + None => {} + } +} + +fn baz(e: upstream::E2) { + match e { + upstream::E2::A | upstream::E2::B => {} + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/match/unreachable-pattern-with-non-exhaustive.stderr b/tests/ui/match/unreachable-pattern-with-non-exhaustive.stderr new file mode 100644 index 0000000000000..9d1c33e811b60 --- /dev/null +++ b/tests/ui/match/unreachable-pattern-with-non-exhaustive.stderr @@ -0,0 +1,69 @@ +error: unreachable pattern + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:17:9 + | +LL | E1::A | E1::B => {} + | ------------- matches all the relevant values +LL | _ => {} + | ^ no value can reach this + | +note: `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:7:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:5:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:25:9 + | +LL | E1::A | E1::B => {} + | ------------- matches all the relevant values +LL | _ => {} + | ^ no value can reach this + | +note: `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:7:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:33:9 + | +LL | E1::A | E1::B => {} + | ------------- matches all the relevant values +LL | _ => {} + | ^ no value can reach this + | +note: `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:7:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:40:30 + | +LL | Some(E1::A | E1::B | _) => {} + | ^ no value can reach this + | +note: multiple earlier patterns match some of the same values + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:40:30 + | +LL | Some(E1::A | E1::B | _) => {} + | ----- ----- ^ collectively making this unreachable + | | | + | | matches some of the same values + | matches some of the same values +note: `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate + --> $DIR/unreachable-pattern-with-non-exhaustive.rs:7:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index 2112344fe6e41..dc95bc846d7f4 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -8,6 +8,11 @@ LL | _ => {} | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types +note: `#[non_exhaustive]` does not affect exhaustiveness checking within the defining crate + --> $DIR/enum_same_crate_empty_match.rs:24:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ note: the lint level is defined here --> $DIR/enum_same_crate_empty_match.rs:3:9 |