diff options
| author | Matthias Krüger <476013+matthiaskrgr@users.noreply.github.com> | 2025-03-19 16:52:54 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-19 16:52:54 +0100 |
| commit | 2ab69b898a96a81767ff6be84c5cc26d144d202f (patch) | |
| tree | d537f150639cd4007c1ce082523fcfd2ec72ce60 /compiler | |
| parent | ce762920140e7a1f75c786b15ed9aa1a345f5cac (diff) | |
| parent | 044deec6824a834ac870e6d081807d432a999807 (diff) | |
| download | rust-2ab69b898a96a81767ff6be84c5cc26d144d202f.tar.gz rust-2ab69b898a96a81767ff6be84c5cc26d144d202f.zip | |
Rollup merge of #138001 - meithecatte:privately-uninhabited, r=Nadrieril
mir_build: consider privacy when checking for irrefutable patterns This PR fixes #137999. Note that, since this makes the compiler reject code that was previously accepted, it will probably need a crater run. I include a commit that factors out a common code pattern into a helper function, purely because the fact that this was repeated all over the place was bothering me. Let me know if I should split that into a separate PR instead.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/src/cast.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/pat.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/types/improper_ctypes.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/adt.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/inhabitedness/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/matches/match_pair.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/errors.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/rustc.rs | 4 |
12 files changed, 46 insertions, 46 deletions
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c85c3b90ce7..8f5fddd19d7 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -43,7 +43,6 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef, elaborate}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; @@ -805,7 +804,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { _ => return Err(CastError::NonScalar), }; if let ty::Adt(adt_def, _) = *self.expr_ty.kind() - && adt_def.did().krate != LOCAL_CRATE + && !adt_def.did().is_local() && adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { return Err(CastError::ForeignNonExhaustiveAdt); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7e8e4e3a561..a75f6f4caac 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1977,7 +1977,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prohibit struct expressions when non-exhaustive flag is set. let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); - if !adt.did().is_local() && variant.is_field_list_non_exhaustive() { + if variant.field_list_has_applicable_non_exhaustive() { self.dcx() .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 35e687f2b0f..c71a5ea8b97 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -20,7 +20,7 @@ use rustc_middle::hir::place::ProjectionKind; pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{ - self, AdtKind, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, + self, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, Span}; @@ -1899,14 +1899,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // to assume that more cases will be added to the variant in the future. This mean // that we should handle non-exhaustive SingleVariant the same way we would handle // a MultiVariant. - // If the variant is not local it must be defined in another crate. - let is_non_exhaustive = match def.adt_kind() { - AdtKind::Struct | AdtKind::Union => { - def.non_enum_variant().is_field_list_non_exhaustive() - } - AdtKind::Enum => def.is_variant_list_non_exhaustive(), - }; - def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive) + def.variants().len() > 1 || def.variant_list_has_applicable_non_exhaustive() } else { false } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 56dae2d7d54..f1f956779c9 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1724,7 +1724,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(); + let non_exhaustive = variant.field_list_has_applicable_non_exhaustive(); if non_exhaustive && !has_rest_pat { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a7186eb48fd..7109fefbe78 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1193,9 +1193,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - let is_non_exhaustive = - def.non_enum_variant().is_field_list_non_exhaustive(); - if is_non_exhaustive && !def.did().is_local() { + if def.non_enum_variant().field_list_has_applicable_non_exhaustive() { return FfiUnsafe { ty, reason: if def.is_struct() { @@ -1248,14 +1246,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - use improper_ctypes::{ - check_non_exhaustive_variant, non_local_and_non_exhaustive, - }; + use improper_ctypes::check_non_exhaustive_variant; - let non_local_def = non_local_and_non_exhaustive(def); + let non_exhaustive = def.variant_list_has_applicable_non_exhaustive(); // Check the contained variants. let ret = def.variants().iter().try_for_each(|variant| { - check_non_exhaustive_variant(non_local_def, variant) + check_non_exhaustive_variant(non_exhaustive, variant) .map_break(|reason| FfiUnsafe { ty, reason, help: None })?; match self.check_variant_for_ffi(acc, ty, def, variant, args) { diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 1030101c545..13afa540afc 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -15,13 +15,13 @@ use crate::fluent_generated as fluent; /// so we don't need the lint to account for it. /// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }. pub(crate) fn check_non_exhaustive_variant( - non_local_def: bool, + non_exhaustive_variant_list: bool, variant: &ty::VariantDef, ) -> ControlFlow<DiagMessage, ()> { // non_exhaustive suggests it is possible that someone might break ABI // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 // so warn on complex enums being used outside their crate - if non_local_def { + if non_exhaustive_variant_list { // which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195 // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }` // but exempt enums with unit ctors like C's (e.g. from rust-bindgen) @@ -30,8 +30,7 @@ pub(crate) fn check_non_exhaustive_variant( } } - let non_exhaustive_variant_fields = variant.is_field_list_non_exhaustive(); - if non_exhaustive_variant_fields && !variant.def_id.is_local() { + if variant.field_list_has_applicable_non_exhaustive() { return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant); } @@ -42,10 +41,3 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool { // CtorKind::Const means a "unit" ctor !matches!(variant.ctor_kind(), Some(CtorKind::Const)) } - -// non_exhaustive suggests it is possible that someone might break ABI -// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 -// so warn on complex enums being used outside their crate -pub(crate) fn non_local_and_non_exhaustive(def: ty::AdtDef<'_>) -> bool { - def.is_variant_list_non_exhaustive() && !def.did().is_local() -} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index c1dc6a894ca..cb245c0aec4 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -327,11 +327,22 @@ impl<'tcx> AdtDef<'tcx> { } /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`. + /// + /// Note that this function will return `true` even if the ADT has been + /// defined in the crate currently being compiled. If that's not what you + /// want, see [`Self::variant_list_has_applicable_non_exhaustive`]. #[inline] pub fn is_variant_list_non_exhaustive(self) -> bool { self.flags().contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) } + /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]` + /// and has been defined in another crate. + #[inline] + pub fn variant_list_has_applicable_non_exhaustive(self) -> bool { + self.is_variant_list_non_exhaustive() && !self.did().is_local() + } + /// Returns the kind of the ADT. #[inline] pub fn adt_kind(self) -> AdtKind { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 4a5f6d80f24..855e5043e84 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -107,7 +107,7 @@ impl<'tcx> Ty<'tcx> { // For now, unions are always considered inhabited Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, // Non-exhaustive ADTs from other crates are always considered inhabited - Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { + Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => { InhabitedPredicate::True } Never => InhabitedPredicate::False, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fc439416a1a..6bdd0a0647d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1208,12 +1208,23 @@ impl VariantDef { } } - /// Is this field list non-exhaustive? + /// Returns `true` if the field list of this variant is `#[non_exhaustive]`. + /// + /// Note that this function will return `true` even if the type has been + /// defined in the crate currently being compiled. If that's not what you + /// want, see [`Self::field_list_has_applicable_non_exhaustive`]. #[inline] pub fn is_field_list_non_exhaustive(&self) -> bool { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } + /// Returns `true` if the field list of this variant is `#[non_exhaustive]` + /// and the type has been defined in another crate. + #[inline] + pub fn field_list_has_applicable_non_exhaustive(&self) -> bool { + self.is_field_list_non_exhaustive() && !self.def_id.is_local() + } + /// Computes the `Ident` of this variant by looking up the `Span` pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index c6f3e22e95f..f2ce0c46dd3 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -273,12 +273,12 @@ impl<'tcx> MatchPairTree<'tcx> { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index - || !v - .inhabited_predicate(cx.tcx, adt_def) - .instantiate(cx.tcx, args) - .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) - }) && (adt_def.did().is_local() - || !adt_def.is_variant_list_non_exhaustive()); + || !v.inhabited_predicate(cx.tcx, adt_def).instantiate(cx.tcx, args).apply( + cx.tcx, + cx.infcx.typing_env(cx.param_env), + cx.def_id.into(), + ) + }) && !adt_def.variant_list_has_applicable_non_exhaustive(); if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 17b22f25dbb..0e16f871b16 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -613,9 +613,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo diag.span_note(span, fluent::mir_build_def_note); } - let is_variant_list_non_exhaustive = matches!(self.ty.kind(), - ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local()); - if is_variant_list_non_exhaustive { + let is_non_exhaustive = matches!(self.ty.kind(), + ty::Adt(def, _) if def.variant_list_has_applicable_non_exhaustive()); + if is_non_exhaustive { diag.note(fluent::mir_build_non_exhaustive_type_note); } else { diag.note(fluent::mir_build_type_note); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 88194c737a6..fec525c9e8c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -150,9 +150,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. pub fn is_foreign_non_exhaustive_enum(&self, ty: RevealedTy<'tcx>) -> bool { match ty.kind() { - ty::Adt(def, ..) => { - def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did().is_local() - } + ty::Adt(def, ..) => def.variant_list_has_applicable_non_exhaustive(), _ => false, } } |
