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`.