diff options
| author | Matthew Kelly <matthew.kelly2@gmail.com> | 2022-08-31 19:39:39 -0400 |
|---|---|---|
| committer | Matthew Kelly <matthew.kelly2@gmail.com> | 2022-08-31 19:39:39 -0400 |
| commit | eda2a401457ba645a32bdc5b9e7e90214e3e4e24 (patch) | |
| tree | 76c4a12cb26666f03aa37a81abe27782def16f1d /compiler/rustc_metadata | |
| parent | 4a443dfb8227d407ff3f0542cb6e688833708ba9 (diff) | |
| parent | 9243168fa5615ec8ebe9164c6bc2fdcccffd08b6 (diff) | |
Merge remote-tracking branch 'origin/master' into mpk/add-long-error-message-for-E0311
Diffstat (limited to 'compiler/rustc_metadata')
| -rw-r--r-- | compiler/rustc_metadata/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/native_libs.rs | 79 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder.rs | 232 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/encoder.rs | 204 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/mod.rs | 5 |
6 files changed, 314 insertions, 241 deletions
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 75069a5f0dc..6440f3e390c 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -4,6 +4,7 @@ #![feature(generators)] #![feature(generic_associated_types)] #![feature(iter_from_generator)] +#![feature(let_chains)] #![feature(let_else)] #![feature(once_cell)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c5e39507d7e..8bafe203748 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -5,7 +5,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; -use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib}; +use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType}; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; use rustc_session::Session; @@ -61,6 +61,7 @@ impl<'tcx> Collector<'tcx> { let mut modifiers = None; let mut cfg = None; let mut wasm_import_module = None; + let mut import_name_type = None; for item in items.iter() { match item.name_or_empty() { sym::name => { @@ -199,9 +200,51 @@ impl<'tcx> Collector<'tcx> { }; wasm_import_module = Some((link_wasm_import_module, item.span())); } + sym::import_name_type => { + if import_name_type.is_some() { + let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute"; + sess.span_err(item.span(), msg); + continue; + } + let Some(link_import_name_type) = item.value_str() else { + let msg = "import name type must be of the form `import_name_type = \"string\"`"; + sess.span_err(item.span(), msg); + continue; + }; + if self.tcx.sess.target.arch != "x86" { + let msg = "import name type is only supported on x86"; + sess.span_err(item.span(), msg); + continue; + } + + let link_import_name_type = match link_import_name_type.as_str() { + "decorated" => PeImportNameType::Decorated, + "noprefix" => PeImportNameType::NoPrefix, + "undecorated" => PeImportNameType::Undecorated, + import_name_type => { + let msg = format!( + "unknown import name type `{import_name_type}`, expected one of: \ + decorated, noprefix, undecorated" + ); + sess.span_err(item.span(), msg); + continue; + } + }; + if !features.raw_dylib { + let span = item.name_value_literal_span().unwrap(); + feature_err( + &sess.parse_sess, + sym::raw_dylib, + span, + "import name type is unstable", + ) + .emit(); + } + import_name_type = Some((link_import_name_type, item.span())); + } _ => { let msg = "unexpected `#[link]` argument, expected one of: \ - name, kind, modifiers, cfg, wasm_import_module"; + name, kind, modifiers, cfg, wasm_import_module, import_name_type"; sess.span_err(item.span(), msg); } } @@ -315,6 +358,14 @@ impl<'tcx> Collector<'tcx> { .emit(); } + // Do this outside of the loop so that `import_name_type` can be specified before `kind`. + if let Some((_, span)) = import_name_type { + if kind != Some(NativeLibKind::RawDylib) { + let msg = "import name type can only be used with link kind `raw-dylib`"; + sess.span_err(span, msg); + } + } + let dll_imports = match kind { Some(NativeLibKind::RawDylib) => { if let Some((name, span)) = name && name.as_str().contains('\0') { @@ -325,7 +376,13 @@ impl<'tcx> Collector<'tcx> { } foreign_mod_items .iter() - .map(|child_item| self.build_dll_import(abi, child_item)) + .map(|child_item| { + self.build_dll_import( + abi, + import_name_type.map(|(import_name_type, _)| import_name_type), + child_item, + ) + }) .collect() } _ => { @@ -486,7 +543,12 @@ impl<'tcx> Collector<'tcx> { .sum() } - fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport { + fn build_dll_import( + &self, + abi: Abi, + import_name_type: Option<PeImportNameType>, + item: &hir::ForeignItemRef, + ) -> DllImport { let calling_convention = if self.tcx.sess.target.arch == "x86" { match abi { Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C, @@ -518,11 +580,18 @@ impl<'tcx> Collector<'tcx> { } }; + let import_name_type = self + .tcx + .codegen_fn_attrs(item.id.def_id) + .link_ordinal + .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord))); + DllImport { name: item.ident.name, - ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal, + import_name_type, calling_convention, span: item.span, + is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(), } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b0d9e4a63f5..d0e0aa91480 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -99,7 +99,7 @@ pub(crate) struct CrateMetadata { /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. - source_map_import_info: OnceCell<Vec<ImportedSourceFile>>, + source_map_import_info: Lock<Vec<Option<ImportedSourceFile>>>, /// For every definition in this crate, maps its `DefPathHash` to its `DefIndex`. def_path_hash_map: DefPathHashMapRef<'static>, /// Likewise for ExpnHash. @@ -143,7 +143,8 @@ pub(crate) struct CrateMetadata { } /// Holds information about a rustc_span::SourceFile imported from another crate. -/// See `imported_source_files()` for more information. +/// See `imported_source_file()` for more information. +#[derive(Clone)] struct ImportedSourceFile { /// This SourceFile's byte-offset within the source_map of its original crate original_start_pos: rustc_span::BytePos, @@ -160,9 +161,6 @@ pub(super) struct DecodeContext<'a, 'tcx> { sess: Option<&'tcx Session>, tcx: Option<TyCtxt<'tcx>>, - // Cache the last used source_file for translating spans as an optimization. - last_source_file_index: usize, - lazy_state: LazyState, // Used for decoding interpret::AllocIds in a cached & thread-safe manner. @@ -191,7 +189,6 @@ pub(super) trait Metadata<'a, 'tcx>: Copy { blob: self.blob(), sess: self.sess().or(tcx.map(|tcx| tcx.sess)), tcx, - last_source_file_index: 0, lazy_state: LazyState::NoNode, alloc_decoding_session: self .cdata() @@ -527,6 +524,9 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { bug!("Cannot decode Span without Session.") }; + // Index of the file in the corresponding crate's list of encoded files. + let metadata_index = u32::decode(decoder); + // There are two possibilities here: // 1. This is a 'local span', which is located inside a `SourceFile` // that came from this crate. In this case, we use the source map data @@ -553,10 +553,10 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { // to be based on the *foreign* crate (e.g. crate C), not the crate // we are writing metadata for (e.g. crate B). This allows us to // treat the 'local' and 'foreign' cases almost identically during deserialization: - // we can call `imported_source_files` for the proper crate, and binary search + // we can call `imported_source_file` for the proper crate, and binary search // through the returned slice using our span. - let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL { - decoder.cdata().imported_source_files(sess) + let source_file = if tag == TAG_VALID_SPAN_LOCAL { + decoder.cdata().imported_source_file(metadata_index, sess) } else { // When we encode a proc-macro crate, all `Span`s should be encoded // with `TAG_VALID_SPAN_LOCAL` @@ -577,60 +577,30 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { cnum ); - // Decoding 'foreign' spans should be rare enough that it's - // not worth it to maintain a per-CrateNum cache for `last_source_file_index`. - // We just set it to 0, to ensure that we don't try to access something out - // of bounds for our initial 'guess' - decoder.last_source_file_index = 0; - let foreign_data = decoder.cdata().cstore.get_crate_data(cnum); - foreign_data.imported_source_files(sess) - }; - - let source_file = { - // Optimize for the case that most spans within a translated item - // originate from the same source_file. - let last_source_file = &imported_source_files[decoder.last_source_file_index]; - - if lo >= last_source_file.original_start_pos && lo <= last_source_file.original_end_pos - { - last_source_file - } else { - let index = imported_source_files - .binary_search_by_key(&lo, |source_file| source_file.original_start_pos) - .unwrap_or_else(|index| index - 1); - - // Don't try to cache the index for foreign spans, - // as this would require a map from CrateNums to indices - if tag == TAG_VALID_SPAN_LOCAL { - decoder.last_source_file_index = index; - } - &imported_source_files[index] - } + foreign_data.imported_source_file(metadata_index, sess) }; - // Make sure our binary search above is correct. + // Make sure our span is well-formed. debug_assert!( - lo >= source_file.original_start_pos && lo <= source_file.original_end_pos, - "Bad binary search: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", + lo + source_file.original_start_pos <= source_file.original_end_pos, + "Malformed encoded span: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", lo, source_file.original_start_pos, source_file.original_end_pos ); - // Make sure we correctly filtered out invalid spans during encoding + // Make sure we correctly filtered out invalid spans during encoding. debug_assert!( - hi >= source_file.original_start_pos && hi <= source_file.original_end_pos, - "Bad binary search: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", + hi + source_file.original_start_pos <= source_file.original_end_pos, + "Malformed encoded span: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", hi, source_file.original_start_pos, source_file.original_end_pos ); - let lo = - (lo + source_file.translated_source_file.start_pos) - source_file.original_start_pos; - let hi = - (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos; + let lo = lo + source_file.translated_source_file.start_pos; + let hi = hi + source_file.translated_source_file.start_pos; // Do not try to decode parent for foreign spans. Span::new(lo, hi, ctxt, None) @@ -661,6 +631,10 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol { sym } + SYMBOL_PREINTERNED => { + let symbol_index = d.read_u32(); + Symbol::new_from_decoded(symbol_index) + } _ => unreachable!(), } } @@ -1482,7 +1456,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. - fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] { + fn imported_source_file(self, source_file_index: u32, sess: &Session) -> ImportedSourceFile { fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> { path.filter(|_| { // Only spend time on further checks if we have what to translate *to*. @@ -1570,90 +1544,96 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } }; - self.cdata.source_map_import_info.get_or_init(|| { - let external_source_map = self.root.source_map.decode(self); - - external_source_map - .map(|source_file_to_import| { - // We can't reuse an existing SourceFile, so allocate a new one - // containing the information we need. - let rustc_span::SourceFile { - mut name, - src_hash, - start_pos, - end_pos, - lines, - multibyte_chars, - non_narrow_chars, - normalized_pos, - name_hash, - .. - } = source_file_to_import; - - // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped - // during rust bootstrapping by `remap-debuginfo = true`, and the user - // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base, - // then we change `name` to a similar state as if the rust was bootstrapped - // with `remap-debuginfo = true`. - // This is useful for testing so that tests about the effects of - // `try_to_translate_virtual_to_real` don't have to worry about how the - // compiler is bootstrapped. - if let Some(virtual_dir) = - &sess.opts.unstable_opts.simulate_remapped_rust_src_base - { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - if let rustc_span::FileName::Real(ref mut old_name) = name { - if let rustc_span::RealFileName::LocalPath(local) = old_name { - if let Ok(rest) = local.strip_prefix(real_dir) { - *old_name = rustc_span::RealFileName::Remapped { - local_path: None, - virtual_name: virtual_dir.join(rest), - }; - } + let mut import_info = self.cdata.source_map_import_info.lock(); + for _ in import_info.len()..=(source_file_index as usize) { + import_info.push(None); + } + import_info[source_file_index as usize] + .get_or_insert_with(|| { + let source_file_to_import = self + .root + .source_map + .get(self, source_file_index) + .expect("missing source file") + .decode(self); + + // We can't reuse an existing SourceFile, so allocate a new one + // containing the information we need. + let rustc_span::SourceFile { + mut name, + src_hash, + start_pos, + end_pos, + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, + name_hash, + .. + } = source_file_to_import; + + // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped + // during rust bootstrapping by `remap-debuginfo = true`, and the user + // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base, + // then we change `name` to a similar state as if the rust was bootstrapped + // with `remap-debuginfo = true`. + // This is useful for testing so that tests about the effects of + // `try_to_translate_virtual_to_real` don't have to worry about how the + // compiler is bootstrapped. + if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base + { + if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { + if let rustc_span::FileName::Real(ref mut old_name) = name { + if let rustc_span::RealFileName::LocalPath(local) = old_name { + if let Ok(rest) = local.strip_prefix(real_dir) { + *old_name = rustc_span::RealFileName::Remapped { + local_path: None, + virtual_name: virtual_dir.join(rest), + }; } } } } + } - // If this file's path has been remapped to `/rustc/$hash`, - // we might be able to reverse that (also see comments above, - // on `try_to_translate_virtual_to_real`). - try_to_translate_virtual_to_real(&mut name); - - let source_length = (end_pos - start_pos).to_usize(); - - let local_version = sess.source_map().new_imported_source_file( - name, - src_hash, - name_hash, - source_length, - self.cnum, - lines, - multibyte_chars, - non_narrow_chars, - normalized_pos, - start_pos, - end_pos, - ); - debug!( - "CrateMetaData::imported_source_files alloc \ + // If this file's path has been remapped to `/rustc/$hash`, + // we might be able to reverse that (also see comments above, + // on `try_to_translate_virtual_to_real`). + try_to_translate_virtual_to_real(&mut name); + + let source_length = (end_pos - start_pos).to_usize(); + + let local_version = sess.source_map().new_imported_source_file( + name, + src_hash, + name_hash, + source_length, + self.cnum, + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, + start_pos, + source_file_index, + ); + debug!( + "CrateMetaData::imported_source_files alloc \ source_file {:?} original (start_pos {:?} end_pos {:?}) \ translated (start_pos {:?} end_pos {:?})", - local_version.name, - start_pos, - end_pos, - local_version.start_pos, - local_version.end_pos - ); + local_version.name, + start_pos, + end_pos, + local_version.start_pos, + local_version.end_pos + ); - ImportedSourceFile { - original_start_pos: start_pos, - original_end_pos: end_pos, - translated_source_file: local_version, - } - }) - .collect() - }) + ImportedSourceFile { + original_start_pos: start_pos, + original_end_pos: end_pos, + translated_source_file: local_version, + } + }) + .clone() } fn get_generator_diagnostic_data( @@ -1716,7 +1696,7 @@ impl CrateMetadata { trait_impls, incoherent_impls: Default::default(), raw_proc_macros, - source_map_import_info: OnceCell::new(), + source_map_import_info: Lock::new(Vec::new()), def_path_hash_map, expn_hash_map: Default::default(), alloc_decoding_state, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 61f16be1d6b..9d201a0c799 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -76,9 +76,9 @@ impl ProcessQueryValue<'_, Option<DeprecationEntry>> for Option<Deprecation> { } macro_rules! provide_one { - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => { + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => { provide_one! { - <$lt> $tcx, $def_id, $other, $cdata, $name => { + $tcx, $def_id, $other, $cdata, $name => { $cdata .root .tables @@ -89,9 +89,9 @@ macro_rules! provide_one { } } }; - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => { + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => { provide_one! { - <$lt> $tcx, $def_id, $other, $cdata, $name => { + $tcx, $def_id, $other, $cdata, $name => { // We don't decode `table_direct`, since it's not a Lazy, but an actual value $cdata .root @@ -102,11 +102,11 @@ macro_rules! provide_one { } } }; - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { - fn $name<$lt>( - $tcx: TyCtxt<$lt>, - def_id_arg: ty::query::query_keys::$name<$lt>, - ) -> ty::query::query_values::$name<$lt> { + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { + fn $name<'tcx>( + $tcx: TyCtxt<'tcx>, + def_id_arg: ty::query::query_keys::$name<'tcx>, + ) -> ty::query::query_values::$name<'tcx> { let _prof_timer = $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); @@ -130,11 +130,11 @@ macro_rules! provide_one { } macro_rules! provide { - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $($name:ident => { $($compute:tt)* })*) => { pub fn provide_extern(providers: &mut ExternProviders) { $(provide_one! { - <$lt> $tcx, $def_id, $other, $cdata, $name => { $($compute)* } + $tcx, $def_id, $other, $cdata, $name => { $($compute)* } })* *providers = ExternProviders { @@ -187,7 +187,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) { } } -provide! { <'tcx> tcx, def_id, other, cdata, +provide! { tcx, def_id, other, cdata, explicit_item_bounds => { table } explicit_predicates_of => { table } generics_of => { table } @@ -199,6 +199,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, codegen_fn_attrs => { table } impl_trait_ref => { table } const_param_default => { table } + object_lifetime_default => { table } thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } @@ -341,7 +342,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); false }, - native_library_kind: |tcx, id| { + native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind), + native_library: |tcx, id| { tcx.native_libraries(id.krate) .iter() .filter(|lib| native_libs::relevant_lib(&tcx.sess, lib)) @@ -355,7 +357,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .foreign_items .contains(&id) }) - .map(|l| l.kind) }, native_libraries: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); @@ -676,6 +677,9 @@ impl CrateStore for CStore { } fn import_source_files(&self, sess: &Session, cnum: CrateNum) { - self.get_crate_data(cnum).imported_source_files(sess); + let cdata = self.get_crate_data(cnum); + for file_index in 0..cdata.root.source_map.size() { + cdata.imported_source_file(file_index as u32, sess); + } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 13436af09b7..3482d9f0451 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -17,7 +17,6 @@ use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items; use rustc_hir::{AnonConst, GenericParamKind}; -use rustc_index::bit_set::GrowableBitSet; use rustc_middle::hir::nested_filter; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -67,13 +66,10 @@ pub(super) struct EncodeContext<'a, 'tcx> { // The indices (into the `SourceMap`'s `MonotonicVec`) // of all of the `SourceFiles` that we need to serialize. // When we serialize a `Span`, we insert the index of its - // `SourceFile` into the `GrowableBitSet`. - // - // This needs to be a `GrowableBitSet` and not a - // regular `BitSet` because we may actually import new `SourceFiles` - // during metadata encoding, due to executing a query - // with a result containing a foreign `Span`. - required_source_files: Option<GrowableBitSet<usize>>, + // `SourceFile` into the `FxIndexSet`. + // The order inside the `FxIndexSet` is used as on-disk + // order of `SourceFiles`, and encoded inside `Span`s. + required_source_files: Option<FxIndexSet<usize>>, is_proc_macro: bool, hygiene_ctxt: &'a HygieneEncodeContext, symbol_table: FxHashMap<Symbol, usize>, @@ -240,17 +236,15 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span { s.source_file_cache = (source_map.files()[source_file_index].clone(), source_file_index); } + let (ref source_file, source_file_index) = s.source_file_cache; + debug_assert!(source_file.contains(span.lo)); - if !s.source_file_cache.0.contains(span.hi) { + if !source_file.contains(span.hi) { // Unfortunately, macro expansion still sometimes generates Spans // that malformed in this way. return TAG_PARTIAL_SPAN.encode(s); } - let source_files = s.required_source_files.as_mut().expect("Already encoded SourceMap!"); - // Record the fact that we need to encode the data for this `SourceFile` - source_files.insert(s.source_file_cache.1); - // There are two possible cases here: // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the // crate we are writing metadata for. When the metadata for *this* crate gets @@ -267,7 +261,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span { // if we're a proc-macro crate. // This allows us to avoid loading the dependencies of proc-macro crates: all of // the information we need to decode `Span`s is stored in the proc-macro crate. - let (tag, lo, hi) = if s.source_file_cache.0.is_imported() && !s.is_proc_macro { + let (tag, metadata_index) = if source_file.is_imported() && !s.is_proc_macro { // To simplify deserialization, we 'rebase' this span onto the crate it originally came from // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values // are relative to the source map information for the 'foreign' crate whose CrateNum @@ -277,29 +271,41 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span { // // All of this logic ensures that the final result of deserialization is a 'normal' // Span that can be used without any additional trouble. - let external_start_pos = { + let metadata_index = { // Introduce a new scope so that we drop the 'lock()' temporary - match &*s.source_file_cache.0.external_src.lock() { - ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos, + match &*source_file.external_src.lock() { + ExternalSource::Foreign { metadata_index, .. } => *metadata_index, src => panic!("Unexpected external source {:?}", src), } }; - let lo = (span.lo - s.source_file_cache.0.start_pos) + external_start_pos; - let hi = (span.hi - s.source_file_cache.0.start_pos) + external_start_pos; - (TAG_VALID_SPAN_FOREIGN, lo, hi) + (TAG_VALID_SPAN_FOREIGN, metadata_index) } else { - (TAG_VALID_SPAN_LOCAL, span.lo, span.hi) + // Record the fact that we need to encode the data for this `SourceFile` + let source_files = + s.required_source_files.as_mut().expect("Already encoded SourceMap!"); + let (metadata_index, _) = source_files.insert_full(source_file_index); + let metadata_index: u32 = + metadata_index.try_into().expect("cannot export more than U32_MAX files"); + + (TAG_VALID_SPAN_LOCAL, metadata_index) }; - tag.encode(s); - lo.encode(s); + // Encode the start position relative to the file start, so we profit more from the + // variable-length integer encoding. + let lo = span.lo - source_file.start_pos; // Encode length which is usually less than span.hi and profits more // from the variable-length integer encoding that we use. - let len = hi - lo; + let len = span.hi - span.lo; + + tag.encode(s); + lo.encode(s); len.encode(s); + // Encode the index of the `SourceFile` for the span, in order to make decoding faster. + metadata_index.encode(s); + if tag == TAG_VALID_SPAN_FOREIGN { // This needs to be two lines to avoid holding the `s.source_file_cache` // while calling `cnum.encode(s)` @@ -311,17 +317,24 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span { impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Symbol { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - match s.symbol_table.entry(*self) { - Entry::Vacant(o) => { - s.opaque.emit_u8(SYMBOL_STR); - let pos = s.opaque.position(); - o.insert(pos); - s.emit_str(self.as_str()); - } - Entry::Occupied(o) => { - let x = o.get().clone(); - s.emit_u8(SYMBOL_OFFSET); - s.emit_usize(x); + // if symbol preinterned, emit tag and symbol index + if self.is_preinterned() { + s.opaque.emit_u8(SYMBOL_PREINTERNED); + s.opaque.emit_u32(self.as_u32()); + } else { + // otherwise write it as string or as offset to it + match s.symbol_table.entry(*self) { + Entry::Vacant(o) => { + s.opaque.emit_u8(SYMBOL_STR); + let pos = s.opaque.position(); + o.insert(pos); + s.emit_str(self.as_str()); + } + Entry::Occupied(o) => { + let x = o.get().clone(); + s.emit_u8(SYMBOL_OFFSET); + s.emit_usize(x); + } } } } @@ -469,7 +482,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) -> LazyArray<rustc_span::SourceFile> { + fn encode_source_map(&mut self) -> LazyTable<u32, LazyValue<rustc_span::SourceFile>> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -480,66 +493,64 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let working_directory = &self.tcx.sess.opts.working_dir; - let adapted = all_source_files - .iter() - .enumerate() - .filter(|(idx, source_file)| { - // Only serialize `SourceFile`s that were used - // during the encoding of a `Span` - required_source_files.contains(*idx) && - // Don't serialize imported `SourceFile`s, unless - // we're in a proc-macro crate. - (!source_file.is_imported() || self.is_proc_macro) - }) - .map(|(_, source_file)| { - // At export time we expand all source file paths to absolute paths because - // downstream compilation sessions can have a different compiler working - // directory, so relative paths from this or any other upstream crate - // won't be valid anymore. - // - // At this point we also erase the actual on-disk path and only keep - // the remapped version -- as is necessary for reproducible builds. - match source_file.name { - FileName::Real(ref original_file_name) => { - let adapted_file_name = - source_map.path_mapping().to_embeddable_absolute_path( - original_file_name.clone(), - working_directory, - ); - - if adapted_file_name != *original_file_name { - let mut adapted: SourceFile = (**source_file).clone(); - adapted.name = FileName::Real(adapted_file_name); - adapted.name_hash = { - let mut hasher: StableHasher = StableHasher::new(); - adapted.name.hash(&mut hasher); - hasher.finish::<u128>() - }; - Lrc::new(adapted) - } else { - // Nothing to adapt - source_file.clone() - } + let mut adapted = TableBuilder::default(); + + // Only serialize `SourceFile`s that were used during the encoding of a `Span`. + // + // The order in which we encode source files is important here: the on-disk format for + // `Span` contains the index of the corresponding `SourceFile`. + for (on_disk_index, &source_file_index) in required_source_files.iter().enumerate() { + let source_file = &all_source_files[source_file_index]; + // Don't serialize imported `SourceFile`s, unless we're in a proc-macro crate. + assert!(!source_file.is_imported() || self.is_proc_macro); + + // At export time we expand all source file paths to absolute paths because + // downstream compilation sessions can have a different compiler working + // directory, so relative paths from this or any other upstream crate + // won't be valid anymore. + // + // At this point we also erase the actual on-disk path and only keep + // the remapped version -- as is necessary for reproducible builds. + let mut source_file = match source_file.name { + FileName::Real(ref original_file_name) => { + let adapted_file_name = source_map + .path_mapping() + .to_embeddable_absolute_path(original_file_name.clone(), working_directory); + + if adapted_file_name != *original_file_name { + let mut adapted: SourceFile = (**source_file).clone(); + adapted.name = FileName::Real(adapted_file_name); + adapted.name_hash = { + let mut hasher: StableHasher = StableHasher::new(); + adapted.name.hash(&mut hasher); + hasher.finish::<u128>() + }; + Lrc::new(adapted) + } else { + // Nothing to adapt + source_file.clone() } - // expanded code, not from a file - _ => source_file.clone(), } - }) - .map(|mut source_file| { - // We're serializing this `SourceFile` into our crate metadata, - // so mark it as coming from this crate. - // This also ensures that we don't try to deserialize the - // `CrateNum` for a proc-macro dependency - since proc macro - // dependencies aren't loaded when we deserialize a proc-macro, - // trying to remap the `CrateNum` would fail. - if self.is_proc_macro { - Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE; - } - source_file - }) - .collect::<Vec<_>>(); + // expanded code, not from a file + _ => source_file.clone(), + }; + + // We're serializing this `SourceFile` into our crate metadata, + // so mark it as coming from this crate. + // This also ensures that we don't try to deserialize the + // `CrateNum` for a proc-macro dependency - since proc macro + // dependencies aren't loaded when we deserialize a proc-macro, + // trying to remap the `CrateNum` would fail. + if self.is_proc_macro { + Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE; + } - self.lazy_array(adapted.iter().map(|rc| &**rc)) + let on_disk_index: u32 = + on_disk_index.try_into().expect("cannot export more than U32_MAX files"); + adapted.set(on_disk_index, self.lazy(source_file)); + } + + adapted.encode(&mut self.opaque) } fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> { @@ -1065,6 +1076,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } } + if let DefKind::TyParam | DefKind::ConstParam = def_kind { + if let Some(default) = self.tcx.object_lifetime_default(def_id) { + record!(self.tables.object_lifetime_default[def_id] <- default); + } + } if let DefKind::Trait | DefKind::TraitAlias = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } @@ -2261,7 +2277,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { let source_map_files = tcx.sess.source_map().files(); let source_file_cache = (source_map_files[0].clone(), 0); - let required_source_files = Some(GrowableBitSet::with_capacity(source_map_files.len())); + let required_source_files = Some(FxIndexSet::default()); drop(source_map_files); let hygiene_ctxt = HygieneEncodeContext::default(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 2bdb1feb677..aeffc85b507 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; @@ -249,7 +250,7 @@ pub(crate) struct CrateRoot { def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>, - source_map: LazyArray<rustc_span::SourceFile>, + source_map: LazyTable<u32, LazyValue<rustc_span::SourceFile>>, compiler_builtins: bool, needs_allocator: bool, @@ -358,6 +359,7 @@ define_tables! { codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>, impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>, const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>, + object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>, optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>, mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, @@ -448,6 +450,7 @@ const TAG_PARTIAL_SPAN: u8 = 2; // Tags for encoding Symbol's const SYMBOL_STR: u8 = 0; const SYMBOL_OFFSET: u8 = 1; +const SYMBOL_PREINTERNED: u8 = 2; pub fn provide(providers: &mut Providers) { encoder::provide(providers); |
