Auto merge of #138001 - meithecatte:privately-uninhabited, r= · rust-lang/rust@5785402 (original) (raw)
17 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -42,7 +42,6 @@ use rustc_middle::ty::error::TypeError; | ||
42 | 42 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef}; |
43 | 43 | use rustc_middle::{bug, span_bug}; |
44 | 44 | use rustc_session::lint; |
45 | -use rustc_span::def_id::LOCAL_CRATE; | |
46 | 45 | use rustc_span::{DUMMY_SP, Span, sym}; |
47 | 46 | use rustc_trait_selection::infer::InferCtxtExt; |
48 | 47 | use rustc_type_ir::elaborate; |
@@ -789,7 +788,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { | ||
789 | 788 | _ => return Err(CastError::NonScalar), |
790 | 789 | }; |
791 | 790 | if let ty::Adt(adt_def, _) = *self.expr_ty.kind() |
792 | - && adt_def.did().krate != LOCAL_CRATE | |
791 | + && !adt_def.did().is_local() | |
793 | 792 | && adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) |
794 | 793 | { |
795 | 794 | return Err(CastError::ForeignNonExhaustiveAdt); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1966,7 +1966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ||
1966 | 1966 | |
1967 | 1967 | // Prohibit struct expressions when non-exhaustive flag is set. |
1968 | 1968 | let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); |
1969 | -if !adt.did().is_local() && variant.is_field_list_non_exhaustive() { | |
1969 | +if variant.field_list_has_applicable_non_exhaustive() { | |
1970 | 1970 | self.dcx() |
1971 | 1971 | .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); |
1972 | 1972 | } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -20,7 +20,7 @@ use rustc_middle::hir::place::ProjectionKind; | ||
20 | 20 | pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; |
21 | 21 | use rustc_middle::mir::FakeReadCause; |
22 | 22 | use rustc_middle::ty::{ |
23 | -self, AdtKind, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, | |
23 | +self, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, | |
24 | 24 | }; |
25 | 25 | use rustc_middle::{bug, span_bug}; |
26 | 26 | use rustc_span::{ErrorGuaranteed, Span}; |
@@ -1834,14 +1834,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx | ||
1834 | 1834 | // to assume that more cases will be added to the variant in the future. This mean |
1835 | 1835 | // that we should handle non-exhaustive SingleVariant the same way we would handle |
1836 | 1836 | // a MultiVariant. |
1837 | -// If the variant is not local it must be defined in another crate. | |
1838 | -let is_non_exhaustive = match def.adt_kind() { | |
1839 | -AdtKind::Struct | AdtKind::Union => { | |
1840 | - def.non_enum_variant().is_field_list_non_exhaustive() | |
1841 | -} | |
1842 | -AdtKind::Enum => def.is_variant_list_non_exhaustive(), | |
1843 | -}; | |
1844 | - def.variants().len() > 1 | | |
1837 | + def.variants().len() > 1 | | |
1845 | 1838 | } else { |
1846 | 1839 | false |
1847 | 1840 | } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1722,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ||
1722 | 1722 | }; |
1723 | 1723 | |
1724 | 1724 | // Require `..` if struct has non_exhaustive attribute. |
1725 | -let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local(); | |
1725 | +let non_exhaustive = variant.field_list_has_applicable_non_exhaustive(); | |
1726 | 1726 | if non_exhaustive && !has_rest_pat { |
1727 | 1727 | self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); |
1728 | 1728 | } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1207,9 +1207,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ||
1207 | 1207 | }; |
1208 | 1208 | } |
1209 | 1209 | |
1210 | -let is_non_exhaustive = | |
1211 | - def.non_enum_variant().is_field_list_non_exhaustive(); | |
1212 | -if is_non_exhaustive && !def.did().is_local() { | |
1210 | +if def.non_enum_variant().field_list_has_applicable_non_exhaustive() { | |
1213 | 1211 | return FfiUnsafe { |
1214 | 1212 | ty, |
1215 | 1213 | reason: if def.is_struct() { |
@@ -1262,14 +1260,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ||
1262 | 1260 | }; |
1263 | 1261 | } |
1264 | 1262 | |
1265 | -use improper_ctypes::{ | |
1266 | - check_non_exhaustive_variant, non_local_and_non_exhaustive, | |
1267 | -}; | |
1263 | +use improper_ctypes::check_non_exhaustive_variant; | |
1268 | 1264 | |
1269 | -let non_local_def = non_local_and_non_exhaustive(def); | |
1265 | +let non_exhaustive = def.variant_list_has_applicable_non_exhaustive(); | |
1270 | 1266 | // Check the contained variants. |
1271 | 1267 | let ret = def.variants().iter().try_for_each(|variant |
1272 | -check_non_exhaustive_variant(non_local_def, variant) | |
1268 | +check_non_exhaustive_variant(non_exhaustive, variant) | |
1273 | 1269 | .map_break(|reason |
1274 | 1270 | |
1275 | 1271 | match self.check_variant_for_ffi(acc, ty, def, variant, args) { |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -15,13 +15,13 @@ use crate::fluent_generated as fluent; | ||
15 | 15 | /// so we don't need the lint to account for it. |
16 | 16 | /// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }. |
17 | 17 | pub(crate) fn check_non_exhaustive_variant( |
18 | -non_local_def: bool, | |
18 | +non_exhaustive_variant_list: bool, | |
19 | 19 | variant: &ty::VariantDef, |
20 | 20 | ) -> ControlFlow<DiagMessage, ()> { |
21 | 21 | // non_exhaustive suggests it is possible that someone might break ABI |
22 | 22 | // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 |
23 | 23 | // so warn on complex enums being used outside their crate |
24 | -if non_local_def { | |
24 | +if non_exhaustive_variant_list { | |
25 | 25 | // which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195 |
26 | 26 | // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }` |
27 | 27 | // 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( | ||
30 | 30 | } |
31 | 31 | } |
32 | 32 | |
33 | -let non_exhaustive_variant_fields = variant.is_field_list_non_exhaustive(); | |
34 | -if non_exhaustive_variant_fields && !variant.def_id.is_local() { | |
33 | +if variant.field_list_has_applicable_non_exhaustive() { | |
35 | 34 | return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant); |
36 | 35 | } |
37 | 36 | |
@@ -42,10 +41,3 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool { | ||
42 | 41 | // CtorKind::Const means a "unit" ctor |
43 | 42 | !matches!(variant.ctor_kind(), Some(CtorKind::Const)) |
44 | 43 | } |
45 | - | |
46 | -// non_exhaustive suggests it is possible that someone might break ABI | |
47 | -// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 | |
48 | -// so warn on complex enums being used outside their crate | |
49 | -pub(crate) fn non_local_and_non_exhaustive(def: ty::AdtDef<'_>) -> bool { | |
50 | - def.is_variant_list_non_exhaustive() && !def.did().is_local() | |
51 | -} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -329,11 +329,22 @@ impl<'tcx> AdtDef<'tcx> { | ||
329 | 329 | } |
330 | 330 | |
331 | 331 | /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`. |
332 | + /// | |
333 | + /// Note that this function will return `true` even if the ADT has been | |
334 | + /// defined in the crate currently being compiled. If that's not what you | |
335 | + /// want, see [`Self::variant_list_has_applicable_non_exhaustive`]. | |
332 | 336 | #[inline] |
333 | 337 | pub fn is_variant_list_non_exhaustive(self) -> bool { |
334 | 338 | self.flags().contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) |
335 | 339 | } |
336 | 340 | |
341 | +/// Returns `true` if the variant list of this ADT is `#[non_exhaustive]` | |
342 | + /// and has been defined in another crate. | |
343 | + #[inline] | |
344 | +pub fn variant_list_has_applicable_non_exhaustive(self) -> bool { | |
345 | +self.is_variant_list_non_exhaustive() && !self.did().is_local() | |
346 | +} | |
347 | + | |
337 | 348 | /// Returns the kind of the ADT. |
338 | 349 | #[inline] |
339 | 350 | pub fn adt_kind(self) -> AdtKind { |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -107,7 +107,7 @@ impl<'tcx> Ty<'tcx> { | ||
107 | 107 | // For now, unions are always considered inhabited |
108 | 108 | Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, |
109 | 109 | // Non-exhaustive ADTs from other crates are always considered inhabited |
110 | -Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { | |
110 | +Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => { | |
111 | 111 | InhabitedPredicate::True |
112 | 112 | } |
113 | 113 | Never => InhabitedPredicate::False, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1206,12 +1206,23 @@ impl VariantDef { | ||
1206 | 1206 | } |
1207 | 1207 | } |
1208 | 1208 | |
1209 | -/// Is this field list non-exhaustive? | |
1209 | +/// Returns `true` if the field list of this variant is `#[non_exhaustive]`. | |
1210 | + /// | |
1211 | + /// Note that this function will return `true` even if the type has been | |
1212 | + /// defined in the crate currently being compiled. If that's not what you | |
1213 | + /// want, see [`Self::field_list_has_applicable_non_exhaustive`]. | |
1210 | 1214 | #[inline] |
1211 | 1215 | pub fn is_field_list_non_exhaustive(&self) -> bool { |
1212 | 1216 | self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) |
1213 | 1217 | } |
1214 | 1218 | |
1219 | +/// Returns `true` if the field list of this variant is `#[non_exhaustive]` | |
1220 | + /// and the type has been defined in another crate. | |
1221 | + #[inline] | |
1222 | +pub fn field_list_has_applicable_non_exhaustive(&self) -> bool { | |
1223 | +self.is_field_list_non_exhaustive() && !self.def_id.is_local() | |
1224 | +} | |
1225 | + | |
1215 | 1226 | /// Computes the `Ident` of this variant by looking up the `Span` |
1216 | 1227 | pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { |
1217 | 1228 | Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -219,12 +219,12 @@ impl<'tcx> MatchPairTree<'tcx> { | ||
219 | 219 | |
220 | 220 | let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v) |
221 | 221 | i == variant_index |
222 | - | | |
223 | -.inhabited_predicate(cx.tcx, adt_def) | |
224 | -.instantiate(cx.tcx, args) | |
225 | -.apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) | |
226 | -}) && (adt_def.did().is_local() | |
227 | - | | |
222 | + | | |
223 | + cx.tcx, | |
224 | +cx.infcx.typing_env(cx.param_env), | |
225 | + cx.def_id.into(), | |
226 | + ) | |
227 | +}) && !adt_def.variant_list_has_applicable_non_exhaustive(); | |
228 | 228 | if irrefutable { |
229 | 229 | default_irrefutable() |
230 | 230 | } else { |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -613,9 +613,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo | ||
613 | 613 | diag.span_note(span, fluent::mir_build_def_note); |
614 | 614 | } |
615 | 615 | |
616 | -let is_variant_list_non_exhaustive = matches!(self.ty.kind(), | |
617 | - ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local()); | |
618 | -if is_variant_list_non_exhaustive { | |
616 | +let is_non_exhaustive = matches!(self.ty.kind(), | |
617 | + ty::Adt(def, _) if def.variant_list_has_applicable_non_exhaustive()); | |
618 | +if is_non_exhaustive { | |
619 | 619 | diag.note(fluent::mir_build_non_exhaustive_type_note); |
620 | 620 | } else { |
621 | 621 | diag.note(fluent::mir_build_type_note); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -150,9 +150,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { | ||
150 | 150 | /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. |
151 | 151 | pub fn is_foreign_non_exhaustive_enum(&self, ty: RevealedTy<'tcx>) -> bool { |
152 | 152 | match ty.kind() { |
153 | - ty::Adt(def, ..) => { | |
154 | - def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did().is_local() | |
155 | -} | |
153 | + ty::Adt(def, ..) => def.variant_list_has_applicable_non_exhaustive(), | |
156 | 154 | _ => false, |
157 | 155 | } |
158 | 156 | } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { | ||
134 | 134 | && let ty::Adt(adt, args) = *binding_type.kind() |
135 | 135 | && adt.is_struct() |
136 | 136 | && let variant = adt.non_enum_variant() |
137 | - && (adt.did().is_local() | | |
137 | + && !variant.field_list_has_applicable_non_exhaustive() | |
138 | 138 | && let module_did = cx.tcx.parent_module(stmt.hir_id) |
139 | 139 | && variant |
140 | 140 | .fields |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -54,8 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { | ||
54 | 54 | if let ExprKind::Struct(_, fields, StructTailExpr::Base(base)) = expr.kind { |
55 | 55 | let ty = cx.typeck_results().expr_ty(expr); |
56 | 56 | if let ty::Adt(def, _) = ty.kind() { |
57 | -if fields.len() == def.non_enum_variant().fields.len() | |
58 | - && !def.variant(0_usize.into()).is_field_list_non_exhaustive() | |
57 | +let variant = def.non_enum_variant(); | |
58 | +if fields.len() == variant.fields.len() | |
59 | + && !variant.is_field_list_non_exhaustive() | |
59 | 60 | { |
60 | 61 | span_lint( |
61 | 62 | cx, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -51,7 +51,7 @@ impl LateLintPass<'_> for UnneededStructPattern { | ||
51 | 51 | let variant = cx.tcx.adt_def(enum_did).variant_with_id(did); |
52 | 52 | |
53 | 53 | let has_only_fields_brackets = variant.ctor.is_some() && variant.fields.is_empty(); |
54 | -let non_exhaustive_activated = !variant.def_id.is_local() && variant.is_field_list_non_exhaustive(); | |
54 | +let non_exhaustive_activated = variant.field_list_has_applicable_non_exhaustive(); | |
55 | 55 | if !has_only_fields_brackets | |
56 | 56 | return; |
57 | 57 | } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
1 | +//@ edition:2024 | |
2 | +//@ check-fail | |
3 | + | |
4 | +mod m { | |
5 | +enum Void {} | |
6 | + | |
7 | +pub struct Internal { | |
8 | +_v: Void, | |
9 | +} | |
10 | + | |
11 | +pub enum Test { | |
12 | +A(u32, u32), | |
13 | +B(Internal), | |
14 | +} | |
15 | +} | |
16 | + | |
17 | +use m::Test; | |
18 | + | |
19 | +pub fn f1(x: &mut Test) { | |
20 | +let r1: &mut u32 = match x { | |
21 | +Test::A(a, _) => a, | |
22 | + _ => todo!(), | |
23 | +}; | |
24 | + | |
25 | +let r2: &mut u32 = match x { //~ ERROR cannot use `*x` because it was mutably borrowed | |
26 | +Test::A(_, b) => b, | |
27 | + _ => todo!(), | |
28 | +}; | |
29 | + | |
30 | +let _ = *r1; | |
31 | +let _ = *r2; | |
32 | +} | |
33 | + | |
34 | +pub fn f2(x: &mut Test) { | |
35 | +let r = &mut *x; | |
36 | +match x { //~ ERROR cannot use `*x` because it was mutably borrowed | |
37 | +Test::A(_, _) => {} | |
38 | + _ => {} | |
39 | +} | |
40 | + | |
41 | +let _ = r; | |
42 | +} | |
43 | + | |
44 | +fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
1 | +error[E0503]: cannot use `*x` because it was mutably borrowed | |
2 | + --> $DIR/privately-uninhabited-issue-137999.rs:25:30 | |
3 | + | | |
4 | +LL | Test::A(a, _) => a, | |
5 | + | - `x.0` is borrowed here | |
6 | +... | |
7 | +LL | let r2: &mut u32 = match x { | |
8 | + | ^ use of borrowed `x.0` | |
9 | +... | |
10 | +LL | let _ = *r1; | |
11 | + | --- borrow later used here | |
12 | + | |
13 | +error[E0503]: cannot use `*x` because it was mutably borrowed | |
14 | + --> $DIR/privately-uninhabited-issue-137999.rs:36:11 | |
15 | + | | |
16 | +LL | let r = &mut *x; | |
17 | + | ------- `*x` is borrowed here | |
18 | +LL | match x { | |
19 | + | ^ use of borrowed `*x` | |
20 | +... | |
21 | +LL | let _ = r; | |
22 | + | - borrow later used here | |
23 | + | |
24 | +error: aborting due to 2 previous errors | |
25 | + | |
26 | +For more information about this error, try `rustc --explain E0503`. |