diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 98bec3f6eac..635219146d0 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -181,8 +181,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } PatKind::Path(_) => self.check_pat_path(pat, path_res.unwrap(), expected, ti), - PatKind::Struct(ref qpath, fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) + PatKind::Struct(ref qpath, fields, has_rest_pat) => { + self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) } PatKind::Or(pats) => { let parent_pat = Some(pat); @@ -712,7 +712,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, qpath: &hir::QPath<'_>, fields: &'tcx [hir::PatField<'tcx>], - etc: bool, + has_rest_pat: bool, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, @@ -734,7 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, pat, variant, fields, etc, def_bm, ti) { + if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) { pat_ty } else { self.tcx.ty_error() @@ -1216,7 +1216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], - etc: bool, + has_rest_pat: bool, def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> bool { @@ -1290,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Require `..` if struct has non_exhaustive attribute. let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local(); - if non_exhaustive && !etc { + if non_exhaustive && !has_rest_pat { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } @@ -1302,7 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .struct_span_err(pat.span, "union patterns should have exactly one field") .emit(); } - if etc { + if has_rest_pat { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !unmentioned_fields.is_empty() { @@ -1313,9 +1313,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) }) .collect(); - if non_exhaustive { - self.non_exhaustive_reachable_pattern(pat, &accessible_unmentioned_fields, adt_ty) - } else if !etc { + + if !has_rest_pat { if accessible_unmentioned_fields.is_empty() { unmentioned_err = Some(self.error_no_accessible_fields(pat, fields)); } else { @@ -1326,6 +1325,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields, )); } + } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() { + self.lint_non_exhaustive_omitted_patterns( + pat, + &accessible_unmentioned_fields, + adt_ty, + ) } } match (inexistent_fields_err, unmentioned_err) { @@ -1653,7 +1658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// is not exhaustive enough. /// /// Nb: the partner lint for enums lives in `compiler/rustc_mir_build/src/thir/pattern/usefulness.rs`. - fn non_exhaustive_reachable_pattern( + fn lint_non_exhaustive_omitted_patterns( &self, pat: &Pat<'_>, unmentioned_fields: &[(&ty::FieldDef, Ident)], diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs index 5b2181d2d83..78db6b170bb 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -31,3 +31,11 @@ pub struct NestedStruct { pub foo: u16, pub bar: NormalStruct, } + +#[derive(Default)] +#[non_exhaustive] +pub struct MixedVisFields { + pub a: u16, + pub b: bool, + pub(crate) foo: bool, +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs index 115fd300fa5..c196ded404d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs @@ -10,7 +10,7 @@ use enums::{ EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, VariantNonExhaustive, }; -use structs::{FunctionalRecord, NestedStruct, NormalStruct}; +use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct}; #[non_exhaustive] #[derive(Default)] @@ -141,6 +141,10 @@ fn main() { //~^ some fields are not explicitly listed //~^^ some fields are not explicitly listed + // Ok: this tests https://github.com/rust-lang/rust/issues/89382 + #[warn(non_exhaustive_omitted_patterns)] + let MixedVisFields { a, b, .. } = MixedVisFields::default(); + // Ok: because this only has 1 variant #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { diff --git a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr index aebe2acb6ad..e66fd8008a1 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr @@ -129,13 +129,13 @@ LL | #[deny(non_exhaustive_omitted_patterns)] = note: the matched value is of type `ErrorKind` and the `non_exhaustive_omitted_patterns` attribute was found error: some variants are not matched explicitly - --> $DIR/reachable-patterns.rs:153:9 + --> $DIR/reachable-patterns.rs:157:9 | LL | _ => {} | ^ pattern `A(_)` not covered | note: the lint level is defined here - --> $DIR/reachable-patterns.rs:151:12 + --> $DIR/reachable-patterns.rs:155:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^