From 697419163ad37315fd69bb8179480966a5c3ba6b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 19 Nov 2025 15:28:19 +0000 Subject: [PATCH 1/4] Remove some now-unnecessary impls --- compiler/rustc_metadata/src/rmeta/table.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index fca413cdad8c..4069ce2c98b8 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -196,13 +196,6 @@ fixed_size_enum! { } } -fixed_size_enum! { - hir::Constness { - ( NotConst ) - ( Const ) - } -} - fixed_size_enum! { hir::Defaultness { ( Final ) @@ -218,13 +211,6 @@ fixed_size_enum! { } } -fixed_size_enum! { - ty::Asyncness { - ( Yes ) - ( No ) - } -} - fixed_size_enum! { hir::CoroutineKind { ( Coroutine(hir::Movability::Movable) ) From a3062aac128b0fb83ab5b178288a6a3963e6d39b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 19 Nov 2025 15:31:45 +0000 Subject: [PATCH 2/4] Only encode `hir::Safety::Safe` in metadata. While `Unsafe` is much less common, a failure to encode it would make downstream crates default to `Safe` and think a thing marked as unsafe is actually safe --- compiler/rustc_hir/src/hir.rs | 7 +++- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_metadata/src/rmeta/table.rs | 42 +++++++++++++++----- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index db88de828aaf..ea2f9e6d920f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4186,8 +4186,13 @@ impl<'hir> Item<'hir> { } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[derive(Encodable, Decodable, HashStable_Generic, Default)] pub enum Safety { + /// This is the default variant, because the compiler messing up + /// metadata encoding and failing to encode a `Safe` flag, means + /// downstream crates think a thing is `Unsafe` instead of silently + /// treating an unsafe thing as safe. + #[default] Unsafe, Safe, } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 6c796b3a9c8c..5c7de5f3ff84 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1187,7 +1187,7 @@ impl<'a> CrateMetadataRef<'a> { } fn get_safety(self, id: DefIndex) -> Safety { - self.root.tables.safety.get(self, id).unwrap_or_else(|| self.missing("safety", id)) + self.root.tables.safety.get(self, id) } fn get_default_field(self, id: DefIndex) -> Option { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dca9ed2ef74f..82dc4b0e89da 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1697,7 +1697,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { })); for field in &variant.fields { - self.tables.safety.set_some(field.did.index, field.safety); + self.tables.safety.set(field.did.index, field.safety); } if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 672ebe3de483..8c5737cb9eb6 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -402,6 +402,7 @@ define_tables! { cross_crate_inlinable: Table, asyncness: Table, constness: Table, + safety: Table, - optional: attributes: Table>, @@ -411,7 +412,6 @@ define_tables! { associated_item_or_field_def_ids: Table>, def_kind: Table, visibility: Table>>, - safety: Table, def_span: Table>, def_ident_span: Table>, lookup_stability: Table>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 4069ce2c98b8..7a8190fcf2f7 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -37,8 +37,17 @@ impl IsDefault for ty::Asyncness { impl IsDefault for hir::Constness { fn is_default(&self) -> bool { match self { - rustc_hir::Constness::Const => false, - rustc_hir::Constness::NotConst => true, + hir::Constness::Const => false, + hir::Constness::NotConst => true, + } + } +} + +impl IsDefault for hir::Safety { + fn is_default(&self) -> bool { + match self { + hir::Safety::Safe => false, + hir::Safety::Unsafe => true, } } } @@ -204,13 +213,6 @@ fixed_size_enum! { } } -fixed_size_enum! { - hir::Safety { - ( Unsafe ) - ( Safe ) - } -} - fixed_size_enum! { hir::CoroutineKind { ( Coroutine(hir::Movability::Movable) ) @@ -343,6 +345,28 @@ impl FixedSizeEncoding for hir::Constness { } } +impl FixedSizeEncoding for hir::Safety { + type ByteArray = [u8; 1]; + + #[inline] + fn from_bytes(b: &[u8; 1]) -> Self { + match b[0] { + 0 => hir::Safety::Unsafe, + 1 => hir::Safety::Safe, + _ => unreachable!(), + } + } + + #[inline] + fn write_to_bytes(self, b: &mut [u8; 1]) { + debug_assert!(!self.is_default()); + b[0] = match self { + hir::Safety::Unsafe => 0, + hir::Safety::Safe => 1, + } + } +} + // NOTE(eddyb) there could be an impl for `usize`, which would enable a more // generic `LazyValue` impl, but in the general case we might not need / want // to fit every `usize` in `u32`. From c489b92845235c66253d964e714ac8dec32bed4b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 19 Nov 2025 16:01:09 +0000 Subject: [PATCH 3/4] Not encoding the default is already handled by `set` --- compiler/rustc_metadata/src/rmeta/encoder.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 82dc4b0e89da..ca4cf260dffb 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1524,17 +1524,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if should_encode_constness(def_kind) { let constness = self.tcx.constness(def_id); - match constness { - hir::Constness::Const => self.tables.constness.set(def_id.index, constness), - hir::Constness::NotConst => {} - } + self.tables.constness.set(def_id.index, constness); } if let DefKind::Fn | DefKind::AssocFn = def_kind { let asyncness = tcx.asyncness(def_id); - match asyncness { - ty::Asyncness::Yes => self.tables.asyncness.set(def_id.index, asyncness), - ty::Asyncness::No => {} - } + self.tables.asyncness.set(def_id.index, asyncness); record_array!(self.tables.fn_arg_idents[def_id] <- tcx.fn_arg_idents(def_id)); } if let Some(name) = tcx.intrinsic(def_id) { From b93f2d8b2637f17c7df269955135ef33eedb94df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 19 Nov 2025 16:02:12 +0000 Subject: [PATCH 4/4] Add a macro for defaulted enum encoding, use it for hir::Defaultness and deduplicate the logic for other similar enums --- compiler/rustc_hir/src/hir.rs | 8 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_metadata/src/rmeta/table.rs | 153 +++++++------------ 4 files changed, 68 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ea2f9e6d920f..0db3f456b60b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3841,8 +3841,12 @@ impl IsAsync { } #[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)] +#[derive(Default)] pub enum Defaultness { - Default { has_value: bool }, + Default { + has_value: bool, + }, + #[default] Final, } @@ -4231,8 +4235,8 @@ impl fmt::Display for Safety { #[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)] #[derive(Default)] pub enum Constness { - Const, #[default] + Const, NotConst, } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ca4cf260dffb..9fac68039f52 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1753,7 +1753,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let item = tcx.associated_item(def_id); if matches!(item.container, AssocContainer::Trait | AssocContainer::TraitImpl(_)) { - self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx)); + self.tables.defaultness.set(def_id.index, item.defaultness(tcx)); } record!(self.tables.assoc_container[def_id] <- item.container); @@ -2155,7 +2155,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let header = tcx.impl_trait_header(def_id); record!(self.tables.impl_trait_header[def_id] <- header); - self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); + self.tables.defaultness.set(def_id.index, tcx.defaultness(def_id)); let trait_ref = header.trait_ref.instantiate_identity(); let simplified_self_ty = fast_reject::simplify_type( diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8c5737cb9eb6..ac042c2ca75d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -403,6 +403,7 @@ define_tables! { asyncness: Table, constness: Table, safety: Table, + defaultness: Table, - optional: attributes: Table>, @@ -436,7 +437,6 @@ define_tables! { thir_abstract_const: Table>>>, impl_parent: Table, const_conditions: Table>>, - defaultness: Table, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? coerce_unsized_info: Table>, mir_const_qualif: Table>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 7a8190fcf2f7..4ce313f32a75 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -25,33 +25,6 @@ impl IsDefault for bool { } } -impl IsDefault for ty::Asyncness { - fn is_default(&self) -> bool { - match self { - ty::Asyncness::Yes => false, - ty::Asyncness::No => true, - } - } -} - -impl IsDefault for hir::Constness { - fn is_default(&self) -> bool { - match self { - hir::Constness::Const => false, - hir::Constness::NotConst => true, - } - } -} - -impl IsDefault for hir::Safety { - fn is_default(&self) -> bool { - match self { - hir::Safety::Safe => false, - hir::Safety::Unsafe => true, - } - } -} - impl IsDefault for u32 { fn is_default(&self) -> bool { *self == 0 @@ -139,6 +112,43 @@ macro_rules! fixed_size_enum { } } +macro_rules! defaulted_enum { + ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => { + impl FixedSizeEncoding for $ty { + type ByteArray = [u8; 1]; + + #[inline] + fn from_bytes(b: &[u8; 1]) -> Self { + use $ty::*; + let val = match b[0] { + $(${index()} => $($pat)*,)* + _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]), + }; + // Make sure the first entry is always the default value, + // and none of the other values are the default value + debug_assert_ne!((b[0] != 0), IsDefault::is_default(&val)); + val + } + + #[inline] + fn write_to_bytes(self, b: &mut [u8; 1]) { + debug_assert!(!IsDefault::is_default(&self)); + use $ty::*; + b[0] = match self { + $($($pat)* => ${index()},)* + $($($($upat)*)|+ => unreachable!(),)? + }; + debug_assert_ne!(b[0], 0); + } + } + impl IsDefault for $ty { + fn is_default(&self) -> bool { + <$ty as Default>::default() == *self + } + } + } +} + // Workaround; need const traits to construct bitflags in a const macro_rules! const_macro_kinds { ($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+)) @@ -205,7 +215,7 @@ fixed_size_enum! { } } -fixed_size_enum! { +defaulted_enum! { hir::Defaultness { ( Final ) ( Default { has_value: false } ) @@ -213,6 +223,27 @@ fixed_size_enum! { } } +defaulted_enum! { + ty::Asyncness { + ( No ) + ( Yes ) + } +} + +defaulted_enum! { + hir::Constness { + ( Const ) + ( NotConst ) + } +} + +defaulted_enum! { + hir::Safety { + ( Unsafe ) + ( Safe ) + } +} + fixed_size_enum! { hir::CoroutineKind { ( Coroutine(hir::Movability::Movable) ) @@ -301,72 +332,6 @@ impl FixedSizeEncoding for bool { } } -impl FixedSizeEncoding for ty::Asyncness { - type ByteArray = [u8; 1]; - - #[inline] - fn from_bytes(b: &[u8; 1]) -> Self { - match b[0] { - 0 => ty::Asyncness::No, - 1 => ty::Asyncness::Yes, - _ => unreachable!(), - } - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 1]) { - debug_assert!(!self.is_default()); - b[0] = match self { - ty::Asyncness::No => 0, - ty::Asyncness::Yes => 1, - } - } -} - -impl FixedSizeEncoding for hir::Constness { - type ByteArray = [u8; 1]; - - #[inline] - fn from_bytes(b: &[u8; 1]) -> Self { - match b[0] { - 0 => hir::Constness::NotConst, - 1 => hir::Constness::Const, - _ => unreachable!(), - } - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 1]) { - debug_assert!(!self.is_default()); - b[0] = match self { - hir::Constness::NotConst => 0, - hir::Constness::Const => 1, - } - } -} - -impl FixedSizeEncoding for hir::Safety { - type ByteArray = [u8; 1]; - - #[inline] - fn from_bytes(b: &[u8; 1]) -> Self { - match b[0] { - 0 => hir::Safety::Unsafe, - 1 => hir::Safety::Safe, - _ => unreachable!(), - } - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 1]) { - debug_assert!(!self.is_default()); - b[0] = match self { - hir::Safety::Unsafe => 0, - hir::Safety::Safe => 1, - } - } -} - // NOTE(eddyb) there could be an impl for `usize`, which would enable a more // generic `LazyValue` impl, but in the general case we might not need / want // to fit every `usize` in `u32`.