From 91fdbd73437aa53d1cc74faa41ae62951839f13a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 21 Jan 2023 18:38:14 +0400 Subject: [PATCH] rustc_metadata: Support non-`Option` nullable values in metadata tables This is a convenience feature for cases in which "no value in the table" and "default value in the table" are equivalent. Tables using `Table` are migrated in this PR, some other cases can be migrated later. This helps `DocFlags` in https://github.com/rust-lang/rust/pull/107136 in particular. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 8 +-- .../src/rmeta/decoder/cstore_impl.rs | 7 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 14 ++-- compiler/rustc_metadata/src/rmeta/mod.rs | 39 +++++----- compiler/rustc_metadata/src/rmeta/table.rs | 72 ++++++++----------- 5 files changed, 64 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 44da3fbe300ca..bb2dd290c6d5d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -985,7 +985,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let vis = self.get_visibility(id); let span = self.get_span(id, sess); let macro_rules = match kind { - DefKind::Macro(..) => self.root.tables.macro_rules.get(self, id).is_some(), + DefKind::Macro(..) => self.root.tables.is_macro_rules.get(self, id), _ => false, }; @@ -1283,7 +1283,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { match self.def_kind(id) { DefKind::Macro(_) => { - let macro_rules = self.root.tables.macro_rules.get(self, id).is_some(); + let macro_rules = self.root.tables.is_macro_rules.get(self, id); let body = self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); ast::MacroDef { macro_rules, body: ast::ptr::P(body) } @@ -1595,11 +1595,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_attr_flags(self, index: DefIndex) -> AttrFlags { - self.root.tables.attr_flags.get(self, index).unwrap_or(AttrFlags::empty()) + self.root.tables.attr_flags.get(self, index) } fn get_is_intrinsic(self, index: DefIndex) -> bool { - self.root.tables.is_intrinsic.get(self, index).is_some() + self.root.tables.is_intrinsic.get(self, index) } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2fa645cd9e33d..eebc2f21dfe4e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -226,12 +226,7 @@ provide! { tcx, def_id, other, cdata, deduced_param_attrs => { table } is_type_alias_impl_trait => { debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); - cdata - .root - .tables - .is_type_alias_impl_trait - .get(cdata, def_id.index) - .is_some() + cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2ecaa33d4d315..97f0457ba7116 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -483,7 +483,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map())) } - fn encode_source_map(&mut self) -> LazyTable> { + fn encode_source_map(&mut self) -> LazyTable>> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -1130,7 +1130,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { attr_flags |= AttrFlags::IS_DOC_HIDDEN; } if !attr_flags.is_empty() { - self.tables.attr_flags.set(def_id.local_def_index, attr_flags); + self.tables.attr_flags.set_nullable(def_id.local_def_index, attr_flags); } } @@ -1387,7 +1387,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if impl_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); + self.tables.is_intrinsic.set_nullable(def_id.index, true); } } } @@ -1519,7 +1519,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { - self.tables.macro_rules.set(def_id.index, ()); + self.tables.is_macro_rules.set_nullable(def_id.index, true); } record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } @@ -1529,7 +1529,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) { - self.tables.is_type_alias_impl_trait.set(def_id.index, ()); + self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true); } } hir::ItemKind::Enum(..) => { @@ -1636,7 +1636,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let hir::ItemKind::Fn(..) = item.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); + self.tables.is_intrinsic.set_nullable(def_id.index, true); } } if let hir::ItemKind::Impl { .. } = item.kind { @@ -2038,7 +2038,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let hir::ForeignItemKind::Fn(..) = nitem.kind { if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); + self.tables.is_intrinsic.set_nullable(def_id.index, true); } } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 69690264ae4ea..698b2ebc4732a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -185,9 +185,9 @@ enum LazyState { Previous(NonZeroUsize), } -type SyntaxContextTable = LazyTable>; -type ExpnDataTable = LazyTable>; -type ExpnHashTable = LazyTable>; +type SyntaxContextTable = LazyTable>>; +type ExpnDataTable = LazyTable>>; +type ExpnHashTable = LazyTable>>; #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct ProcMacroData { @@ -253,7 +253,7 @@ pub(crate) struct CrateRoot { def_path_hash_map: LazyValue>, - source_map: LazyTable>, + source_map: LazyTable>>, compiler_builtins: bool, needs_allocator: bool, @@ -315,21 +315,27 @@ pub(crate) struct IncoherentImpls { /// Define `LazyTables` and `TableBuilders` at the same time. macro_rules! define_tables { - ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => { + ( + - nullable: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+ + - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+ + ) => { #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct LazyTables { - $($name: LazyTable<$IDX, $T>),+ + $($name1: LazyTable<$IDX1, $T1>,)+ + $($name2: LazyTable<$IDX2, Option<$T2>>,)+ } #[derive(Default)] struct TableBuilders { - $($name: TableBuilder<$IDX, $T>),+ + $($name1: TableBuilder<$IDX1, $T1>,)+ + $($name2: TableBuilder<$IDX2, Option<$T2>>,)+ } impl TableBuilders { fn encode(&self, buf: &mut FileEncoder) -> LazyTables { LazyTables { - $($name: self.$name.encode(buf)),+ + $($name1: self.$name1.encode(buf),)+ + $($name2: self.$name2.encode(buf),)+ } } } @@ -337,9 +343,15 @@ macro_rules! define_tables { } define_tables! { +- nullable: + is_intrinsic: Table, + is_macro_rules: Table, + is_type_alias_impl_trait: Table, + attr_flags: Table, + +- optional: attributes: Table>, children: Table>, - opt_def_kind: Table, visibility: Table>>, def_span: Table>, @@ -370,7 +382,6 @@ define_tables! { impl_parent: Table, impl_polarity: Table, constness: Table, - is_intrinsic: Table, impl_defaultness: Table, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? coerce_unsized_info: Table>, @@ -380,7 +391,6 @@ define_tables! { fn_arg_names: Table>, generator_kind: Table>, trait_def: Table>, - trait_item_def_id: Table, inherent_impls: Table>, expn_that_defined: Table>, @@ -395,18 +405,12 @@ define_tables! { def_path_hashes: Table, proc_macro_quoted_spans: Table>, generator_diagnostic_data: Table>>, - attr_flags: Table, variant_data: Table>, assoc_container: Table, - // Slot is full when macro is macro_rules. - macro_rules: Table, macro_definition: Table>, proc_macro: Table, module_reexports: Table>, deduced_param_attrs: Table>, - // Slot is full when opaque is TAIT. - is_type_alias_impl_trait: Table, - trait_impl_trait_tys: Table>>>, } @@ -419,6 +423,7 @@ struct VariantData { } bitflags::bitflags! { + #[derive(Default)] pub struct AttrFlags: u8 { const MAY_HAVE_DOC_LINKS = 1 << 0; const IS_DOC_HIDDEN = 1 << 1; diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index dc003227d40bd..70dbf6476e2fa 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -16,6 +16,7 @@ use std::num::NonZeroUsize; /// but this has no impact on safety. pub(super) trait FixedSizeEncoding: Default { /// This should be `[u8; BYTE_LEN]`; + /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations. type ByteArray; fn from_bytes(b: &Self::ByteArray) -> Self; @@ -199,31 +200,31 @@ impl FixedSizeEncoding for Option { } } -impl FixedSizeEncoding for Option { +impl FixedSizeEncoding for AttrFlags { type ByteArray = [u8; 1]; #[inline] fn from_bytes(b: &[u8; 1]) -> Self { - (b[0] != 0).then(|| AttrFlags::from_bits_truncate(b[0])) + AttrFlags::from_bits_truncate(b[0]) } #[inline] fn write_to_bytes(self, b: &mut [u8; 1]) { - b[0] = self.map_or(0, |flags| flags.bits()) + b[0] = self.bits(); } } -impl FixedSizeEncoding for Option<()> { +impl FixedSizeEncoding for bool { type ByteArray = [u8; 1]; #[inline] fn from_bytes(b: &[u8; 1]) -> Self { - (b[0] != 0).then(|| ()) + b[0] != 0 } #[inline] fn write_to_bytes(self, b: &mut [u8; 1]) { - b[0] = self.is_some() as u8 + b[0] = self as u8 } } @@ -273,44 +274,38 @@ impl FixedSizeEncoding for Option> { } /// Helper for constructing a table's serialization (also see `Table`). -pub(super) struct TableBuilder -where - Option: FixedSizeEncoding, -{ - blocks: IndexVec as FixedSizeEncoding>::ByteArray>, +pub(super) struct TableBuilder { + blocks: IndexVec, _marker: PhantomData, } -impl Default for TableBuilder -where - Option: FixedSizeEncoding, -{ +impl Default for TableBuilder { fn default() -> Self { TableBuilder { blocks: Default::default(), _marker: PhantomData } } } -impl TableBuilder +impl TableBuilder> where - Option: FixedSizeEncoding, + Option: FixedSizeEncoding, { - pub(crate) fn set(&mut self, i: I, value: T) - where - Option: FixedSizeEncoding, - { + pub(crate) fn set(&mut self, i: I, value: T) { + self.set_nullable(i, Some(value)) + } +} + +impl> TableBuilder { + pub(crate) fn set_nullable(&mut self, i: I, value: T) { // FIXME(eddyb) investigate more compact encodings for sparse tables. // On the PR @michaelwoerister mentioned: // > Space requirements could perhaps be optimized by using the HAMT `popcnt` // > trick (i.e. divide things into buckets of 32 or 64 items and then // > store bit-masks of which item in each bucket is actually serialized). self.blocks.ensure_contains_elem(i, || [0; N]); - Some(value).write_to_bytes(&mut self.blocks[i]); + value.write_to_bytes(&mut self.blocks[i]); } - pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable - where - Option: FixedSizeEncoding, - { + pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable { let pos = buf.position(); for block in &self.blocks { buf.emit_raw_bytes(block); @@ -323,34 +318,27 @@ where } } -impl LazyTable +impl + ParameterizedOverTcx> + LazyTable where - Option: FixedSizeEncoding, + for<'tcx> T::Value<'tcx>: FixedSizeEncoding, { /// Given the metadata, extract out the value at a particular index (if any). #[inline(never)] - pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>, const N: usize>( - &self, - metadata: M, - i: I, - ) -> Option> - where - Option>: FixedSizeEncoding, - { + pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> { debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size); let start = self.position.get(); let bytes = &metadata.blob()[start..start + self.encoded_size]; let (bytes, []) = bytes.as_chunks::() else { panic!() }; - let bytes = bytes.get(i.index())?; - FixedSizeEncoding::from_bytes(bytes) + match bytes.get(i.index()) { + Some(bytes) => FixedSizeEncoding::from_bytes(bytes), + None => FixedSizeEncoding::from_bytes(&[0; N]), + } } /// Size of the table in entries, including possible gaps. - pub(super) fn size(&self) -> usize - where - for<'tcx> Option>: FixedSizeEncoding, - { + pub(super) fn size(&self) -> usize { self.encoded_size / N } }