rust/compiler/rustc_metadata/src/rmeta/decoder.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1995 lines
74 KiB
Rust
Raw Normal View History

2011-07-07 23:29:09 -07:00
// Decoding metadata from a single crate's metadata
2011-06-27 16:03:01 -07:00
use std::iter::TrustedLen;
use std::path::Path;
use std::sync::{Arc, OnceLock};
use std::{io, iter, mem};
pub(super) use cstore_impl::provide;
use proc_macro::bridge::client::ProcMacro;
2020-04-27 23:26:11 +05:30
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
2024-02-08 21:10:16 +00:00
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::owned_slice::OwnedSlice;
use rustc_data_structures::sync::Lock;
use rustc_data_structures::unhash::UnhashMap;
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
use rustc_hir::Safety;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefPath, DefPathData};
2021-10-04 15:57:39 -05:00
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_index::Idx;
use rustc_middle::middle::lib_features::LibFeatures;
2020-03-29 17:19:48 +02:00
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::ty::Visibility;
2020-03-29 17:19:48 +02:00
use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::{bug, implement_ty_decoder};
use rustc_serialize::opaque::MemDecoder;
use rustc_serialize::{Decodable, Decoder};
use rustc_session::Session;
use rustc_session::config::TargetModifier;
use rustc_session::cstore::{CrateSource, ExternCrate};
use rustc_span::hygiene::HygieneDecodeContext;
use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw};
use tracing::debug;
use crate::creader::CStore;
use crate::rmeta::table::IsDefault;
use crate::rmeta::*;
mod cstore_impl;
/// A reference to the raw binary version of crate metadata.
/// This struct applies [`MemDecoder`]'s validation when constructed
/// so that later constructions are guaranteed to succeed.
pub(crate) struct MetadataBlob(OwnedSlice);
impl std::ops::Deref for MetadataBlob {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
&self.0[..]
}
}
impl MetadataBlob {
2024-05-21 20:12:07 -04:00
/// Runs the [`MemDecoder`] validation and if it passes, constructs a new [`MetadataBlob`].
pub(crate) fn new(slice: OwnedSlice) -> Result<Self, ()> {
2024-05-21 20:12:07 -04:00
if MemDecoder::new(&slice, 0).is_ok() { Ok(Self(slice)) } else { Err(()) }
}
2024-05-21 20:12:07 -04:00
/// Since this has passed the validation of [`MetadataBlob::new`], this returns bytes which are
/// known to pass the [`MemDecoder`] validation.
pub(crate) fn bytes(&self) -> &OwnedSlice {
&self.0
}
}
/// A map from external crate numbers (as decoded from some crate file) to
/// local crate numbers (as generated during this session). Each external
/// crate may refer to types in other external crates, and each has their
/// own crate numbers.
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
/// Target modifiers - abi or exploit mitigations flags
pub(crate) type TargetModifiers = Vec<TargetModifier>;
pub(crate) struct CrateMetadata {
/// The primary crate data - binary metadata blob.
blob: MetadataBlob,
// --- Some data pre-decoded from the metadata blob, usually for performance ---
/// Data about the top-level items in a crate, as well as various crate-level metadata.
root: CrateRoot,
/// Trait impl data.
/// FIXME: Used only from queries and can use query cache,
/// so pre-decoding can probably be avoided.
2024-02-08 21:10:16 +00:00
trait_impls: FxIndexMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>,
/// Inherent impls which do not follow the normal coherence rules.
///
2022-03-30 11:24:26 +02:00
/// These can be introduced using either `#![rustc_coherence_is_core]`
/// or `#[rustc_allow_incoherent_impl]`.
2024-02-08 21:10:16 +00:00
incoherent_impls: FxIndexMap<SimplifiedType, LazyArray<DefIndex>>,
/// 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.
2022-08-06 23:27:45 +02:00
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.
2023-09-01 01:14:33 +02:00
expn_hash_map: OnceLock<UnhashMap<ExpnHash, ExpnIndex>>,
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
alloc_decoding_state: AllocDecodingState,
/// Caches decoded `DefKey`s.
def_key_cache: Lock<FxHashMap<DefIndex, DefKey>>,
// --- Other significant crate properties ---
/// ID of this crate, from the current compilation session's point of view.
cnum: CrateNum,
/// Maps crate IDs as they are were seen from this crate's compilation sessions into
/// IDs as they are seen from the current compilation session.
cnum_map: CrateNumMap,
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
dependencies: Vec<CrateNum>,
/// How to link (or not link) this crate to the currently compiled crate.
dep_kind: CrateDepKind,
/// Filesystem location of this crate.
source: Arc<CrateSource>,
2023-05-08 12:04:27 -07:00
/// Whether or not this crate should be consider a private dependency.
/// Used by the 'exported_private_dependencies' lint, and for determining
/// whether to emit suggestions that reference this crate.
private_dep: bool,
/// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
host_hash: Option<Svh>,
/// The crate was used non-speculatively.
used: bool,
2020-03-17 11:45:02 -04:00
/// Additional data used for decoding `HygieneData` (e.g. `SyntaxContext`
/// and `ExpnId`).
/// Note that we store a `HygieneDecodeContext` for each `CrateMetadata`. This is
2020-03-17 11:45:02 -04:00
/// because `SyntaxContext` ids are not globally unique, so we need
/// to track which ids we've decoded on a per-crate basis.
hygiene_context: HygieneDecodeContext,
2020-03-17 11:45:02 -04:00
// --- Data used only for improving diagnostics ---
/// Information about the `extern crate` item or path that caused this crate to be loaded.
/// If this is `None`, then the crate was injected (e.g., by the allocator).
extern_crate: Option<ExternCrate>,
}
/// Holds information about a rustc_span::SourceFile imported from another crate.
2022-08-06 23:00:49 +02:00
/// 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,
/// The end of this SourceFile within the source_map of its original crate
original_end_pos: rustc_span::BytePos,
/// The imported SourceFile's representation within the local source_map
translated_source_file: Arc<rustc_span::SourceFile>,
}
pub(super) struct DecodeContext<'a, 'tcx> {
opaque: MemDecoder<'a>,
cdata: Option<CrateMetadataRef<'a>>,
blob: &'a MetadataBlob,
sess: Option<&'tcx Session>,
2019-06-14 00:48:52 +03:00
tcx: Option<TyCtxt<'tcx>>,
2016-10-23 08:32:37 +05:30
lazy_state: LazyState,
// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
alloc_decoding_session: Option<AllocDecodingSession<'a>>,
}
/// Abstract over the various ways one can create metadata decoders.
pub(super) trait Metadata<'a, 'tcx>: Copy {
fn blob(self) -> &'a MetadataBlob;
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
None
}
fn sess(self) -> Option<&'tcx Session> {
None
}
fn tcx(self) -> Option<TyCtxt<'tcx>> {
None
}
fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
let tcx = self.tcx();
DecodeContext {
// FIXME: This unwrap should never panic because we check that it won't when creating
// `MetadataBlob`. Ideally we'd just have a `MetadataDecoder` and hand out subslices of
// it as we do elsewhere in the compiler using `MetadataDecoder::split_at`. But we own
// the data for the decoder so holding onto the `MemDecoder` too would make us a
// self-referential struct which is downright goofy because `MetadataBlob` is already
// self-referential. Probably `MemDecoder` should contain an `OwnedSlice`, but that
// demands a significant refactoring due to our crate graph.
opaque: MemDecoder::new(self.blob(), pos).unwrap(),
cdata: self.cdata(),
blob: self.blob(),
sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
tcx,
2016-10-23 08:32:37 +05:30
lazy_state: LazyState::NoNode,
alloc_decoding_session: self
.cdata()
.map(|cdata| cdata.cdata.alloc_decoding_state.new_decoding_session()),
}
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
#[inline]
fn blob(self) -> &'a MetadataBlob {
self
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) {
#[inline]
fn blob(self) -> &'a MetadataBlob {
self.0
}
#[inline]
fn sess(self) -> Option<&'tcx Session> {
let (_, sess) = self;
Some(sess)
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> {
#[inline]
fn blob(self) -> &'a MetadataBlob {
&self.cdata.blob
2016-10-23 08:32:37 +05:30
}
#[inline]
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
Some(self)
2016-10-23 08:32:37 +05:30
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) {
#[inline]
fn blob(self) -> &'a MetadataBlob {
&self.0.cdata.blob
}
#[inline]
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
Some(self.0)
}
#[inline]
fn sess(self) -> Option<&'tcx Session> {
Some(self.1)
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) {
#[inline]
fn blob(self) -> &'a MetadataBlob {
&self.0.cdata.blob
2016-10-23 08:32:37 +05:30
}
#[inline]
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
Some(self.0)
2016-10-23 08:32:37 +05:30
}
#[inline]
2019-06-14 00:48:52 +03:00
fn tcx(self) -> Option<TyCtxt<'tcx>> {
2016-10-23 08:32:37 +05:30
Some(self.1)
}
}
impl<T: ParameterizedOverTcx> LazyValue<T> {
2023-07-14 07:50:02 -04:00
#[inline]
fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>(self, metadata: M) -> T::Value<'tcx>
where
T::Value<'tcx>: Decodable<DecodeContext<'a, 'tcx>>,
{
let mut dcx = metadata.decoder(self.position.get());
dcx.lazy_state = LazyState::NodeStart(self.position);
T::Value::decode(&mut dcx)
}
}
struct DecodeIterator<'a, 'tcx, T> {
elem_counter: std::ops::Range<usize>,
dcx: DecodeContext<'a, 'tcx>,
_phantom: PhantomData<fn() -> T>,
}
impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Iterator for DecodeIterator<'a, 'tcx, T> {
type Item = T;
2022-02-17 21:33:23 +01:00
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.elem_counter.next().map(|_| T::decode(&mut self.dcx))
2022-02-17 21:33:23 +01:00
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.elem_counter.size_hint()
}
2022-02-17 21:33:23 +01:00
}
impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> ExactSizeIterator
for DecodeIterator<'a, 'tcx, T>
2022-02-17 21:33:23 +01:00
{
fn len(&self) -> usize {
self.elem_counter.len()
}
}
unsafe impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> TrustedLen
for DecodeIterator<'a, 'tcx, T>
{
2022-02-17 21:33:23 +01:00
}
impl<T: ParameterizedOverTcx> LazyArray<T> {
2023-07-14 07:50:02 -04:00
#[inline]
fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>(
self,
metadata: M,
) -> DecodeIterator<'a, 'tcx, T::Value<'tcx>>
where
T::Value<'tcx>: Decodable<DecodeContext<'a, 'tcx>>,
{
let mut dcx = metadata.decoder(self.position.get());
dcx.lazy_state = LazyState::NodeStart(self.position);
DecodeIterator { elem_counter: (0..self.num_elems), dcx, _phantom: PhantomData }
2022-04-10 00:16:55 +02:00
}
}
impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
let Some(tcx) = self.tcx else {
bug!(
"No TyCtxt found for decoding. \
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."
);
};
tcx
}
#[inline]
pub(crate) fn blob(&self) -> &'a MetadataBlob {
self.blob
}
#[inline]
fn cdata(&self) -> CrateMetadataRef<'a> {
debug_assert!(self.cdata.is_some(), "missing CrateMetadata in DecodeContext");
self.cdata.unwrap()
}
2022-04-10 00:16:55 +02:00
#[inline]
fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
2022-04-10 00:16:55 +02:00
self.cdata().map_encoded_cnum_to_current(cnum)
}
#[inline]
2024-01-29 23:59:09 +01:00
fn read_lazy_offset_then<T>(&mut self, f: impl Fn(NonZero<usize>) -> T) -> T {
2022-01-18 13:22:50 +11:00
let distance = self.read_usize();
let position = match self.lazy_state {
LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
LazyState::NodeStart(start) => {
let start = start.get();
assert!(distance <= start);
start - distance
}
LazyState::Previous(last_pos) => last_pos.get() + distance,
};
let position = NonZero::new(position).unwrap();
self.lazy_state = LazyState::Previous(position);
f(position)
}
fn read_lazy<T>(&mut self) -> LazyValue<T> {
self.read_lazy_offset_then(|pos| LazyValue::from_position(pos))
}
fn read_lazy_array<T>(&mut self, len: usize) -> LazyArray<T> {
self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len))
}
2023-07-10 10:45:24 -04:00
fn read_lazy_table<I, T>(&mut self, width: usize, len: usize) -> LazyTable<I, T> {
self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, width, len))
}
#[inline]
fn read_raw_bytes(&mut self, len: usize) -> &[u8] {
self.opaque.read_raw_bytes(len)
}
}
2025-03-13 17:53:36 +00:00
impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
const CLEAR_CROSS_CRATE: bool = true;
#[inline]
2025-03-13 17:53:36 +00:00
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx()
}
2022-01-18 13:22:50 +11:00
fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
where
2022-01-18 13:22:50 +11:00
F: FnOnce(&mut Self) -> Ty<'tcx>,
{
let tcx = self.tcx();
let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
2020-06-10 09:26:54 +01:00
if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
2022-01-18 13:22:50 +11:00
return ty;
}
2022-01-18 13:22:50 +11:00
let ty = or_insert_with(self);
2020-06-10 09:26:54 +01:00
tcx.ty_rcache.borrow_mut().insert(key, ty);
2022-01-18 13:22:50 +11:00
ty
}
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
let new_opaque = self.opaque.split_at(pos);
let old_opaque = mem::replace(&mut self.opaque, new_opaque);
let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
let r = f(self);
self.opaque = old_opaque;
self.lazy_state = old_state;
r
}
2022-01-18 13:22:50 +11:00
fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId {
if let Some(alloc_decoding_session) = self.alloc_decoding_session {
alloc_decoding_session.decode_alloc_id(self)
} else {
bug!("Attempting to decode interpret::AllocId without CrateMetadata")
}
}
}
2021-07-10 23:34:41 +02:00
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex {
2023-07-14 07:50:02 -04:00
#[inline]
2022-01-18 13:22:50 +11:00
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex {
ExpnIndex::from_u32(d.read_u32())
2021-07-10 23:34:41 +02:00
}
}
impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> {
fn decode_attr_id(&mut self) -> rustc_span::AttrId {
let sess = self.sess.expect("can't decode AttrId without Session");
sess.psess.attr_id_generator.mk_attr_id()
2022-09-02 16:29:40 +08:00
}
fn decode_crate_num(&mut self) -> CrateNum {
let cnum = CrateNum::from_u32(self.read_u32());
self.map_encoded_cnum_to_current(cnum)
}
fn decode_def_index(&mut self) -> DefIndex {
DefIndex::from_u32(self.read_u32())
}
fn decode_def_id(&mut self) -> DefId {
DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
}
fn decode_syntax_context(&mut self) -> SyntaxContext {
let cdata = self.cdata();
let Some(sess) = self.sess else {
bug!(
"Cannot decode SyntaxContext without Session.\
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."
);
};
let cname = cdata.root.name();
rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| {
debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
2022-01-18 13:22:50 +11:00
cdata
.root
.syntax_contexts
.get(cdata, id)
.unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}"))
2022-01-18 13:22:50 +11:00
.decode((cdata, sess))
})
}
fn decode_expn_id(&mut self) -> ExpnId {
let local_cdata = self.cdata();
let Some(sess) = self.sess else {
bug!(
"Cannot decode ExpnId without Session. \
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."
);
};
let cnum = CrateNum::decode(self);
let index = u32::decode(self);
2021-06-27 10:38:06 +02:00
let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| {
let ExpnId { krate: cnum, local_id: index } = expn_id;
// Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s
// are stored in the owning crate, to avoid duplication.
2021-06-27 10:03:10 +02:00
debug_assert_ne!(cnum, LOCAL_CRATE);
let crate_data = if cnum == local_cdata.cnum {
local_cdata
} else {
local_cdata.cstore.get_crate_data(cnum)
};
let expn_data = crate_data
.root
.expn_data
.get(crate_data, index)
.unwrap()
.decode((crate_data, sess));
let expn_hash = crate_data
.root
.expn_hashes
.get(crate_data, index)
.unwrap()
.decode((crate_data, sess));
2021-06-27 10:03:10 +02:00
(expn_data, expn_hash)
2021-06-27 10:38:06 +02:00
});
2022-01-18 13:22:50 +11:00
expn_id
}
fn decode_span(&mut self) -> Span {
let start = self.position();
let tag = SpanTag(self.peek_byte());
let data = if tag.kind() == SpanKind::Indirect {
// Skip past the tag we just peek'd.
self.read_u8();
// indirect tag lengths are safe to access, since they're (0, 8)
let bytes_needed = tag.length().unwrap().0 as usize;
let mut total = [0u8; usize::BITS as usize / 8];
total[..bytes_needed].copy_from_slice(self.read_raw_bytes(bytes_needed));
let offset_or_position = usize::from_le_bytes(total);
let position = if tag.is_relative_offset() {
start - offset_or_position
} else {
offset_or_position
};
self.with_position(position, SpanData::decode)
} else {
SpanData::decode(self)
};
data.span()
}
fn decode_symbol(&mut self) -> Symbol {
let tag = self.read_u8();
match tag {
SYMBOL_STR => {
let s = self.read_str();
Symbol::intern(s)
}
SYMBOL_OFFSET => {
// read str offset
let pos = self.read_usize();
// move to str offset and read
self.opaque.with_position(pos, |d| {
let s = d.read_str();
Symbol::intern(s)
})
}
SYMBOL_PREINTERNED => {
let symbol_index = self.read_u32();
Symbol::new_from_decoded(symbol_index)
}
_ => unreachable!(),
}
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData {
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SpanData {
let tag = SpanTag::decode(decoder);
let ctxt = tag.context().unwrap_or_else(|| SyntaxContext::decode(decoder));
if tag.kind() == SpanKind::Partial {
return DUMMY_SP.with_ctxt(ctxt).data();
}
debug_assert!(tag.kind() == SpanKind::Local || tag.kind() == SpanKind::Foreign);
2022-01-18 13:22:50 +11:00
let lo = BytePos::decode(decoder);
let len = tag.length().unwrap_or_else(|| BytePos::decode(decoder));
let hi = lo + len;
let Some(sess) = decoder.sess else {
bug!(
"Cannot decode Span without Session. \
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."
)
};
// Index of the file in the corresponding crate's list of encoded files.
2022-08-06 23:00:49 +02:00
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
// encoded in this crate. This branch should be taken nearly all of the time.
// 2. This is a 'foreign span', which is located inside a `SourceFile`
// that came from a *different* crate (some crate upstream of the one
// whose metadata we're looking at). For example, consider this dependency graph:
//
// A -> B -> C
//
// Suppose that we're currently compiling crate A, and start deserializing
// metadata from crate B. When we deserialize a Span from crate B's metadata,
// there are two possibilities:
//
// 1. The span references a file from crate B. This makes it a 'local' span,
// which means that we can use crate B's serialized source map information.
// 2. The span references a file from crate C. This makes it a 'foreign' span,
// which means we need to use Crate *C* (not crate B) to determine the source
// map information. We only record source map information for a file in the
// crate that 'owns' it, so deserializing a Span may require us to look at
// a transitive dependency.
//
// When we encode a foreign span, we adjust its 'lo' and 'high' values
// 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:
2022-08-06 23:00:49 +02:00
// we can call `imported_source_file` for the proper crate, and binary search
// through the returned slice using our span.
let source_file = if tag.kind() == SpanKind::Local {
2022-08-06 23:00:49 +02:00
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`
if decoder.cdata().root.is_proc_macro_crate() {
// Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE
// since we don't have `cnum_map` populated.
2022-01-18 13:22:50 +11:00
let cnum = u32::decode(decoder);
panic!(
"Decoding of crate {:?} tried to access proc-macro dep {:?}",
decoder.cdata().root.header.name,
cnum
);
}
// tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above
2022-01-18 13:22:50 +11:00
let cnum = CrateNum::decode(decoder);
debug!(
"SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}",
cnum
);
let foreign_data = decoder.cdata().cstore.get_crate_data(cnum);
2022-08-06 23:00:49 +02:00
foreign_data.imported_source_file(metadata_index, sess)
};
// Make sure our span is well-formed.
debug_assert!(
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.
debug_assert!(
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;
let hi = hi + source_file.translated_source_file.start_pos;
// Do not try to decode parent for foreign spans (it wasn't encoded in the first place).
SpanData { lo, hi, ctxt, parent: None }
}
}
2023-06-19 20:46:46 +00:00
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
ty::codec::RefDecodable::decode(d)
}
}
impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyValue<T> {
2022-01-18 13:22:50 +11:00
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
decoder.read_lazy()
}
}
impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyArray<T> {
2023-07-14 07:50:02 -04:00
#[inline]
2022-01-18 13:22:50 +11:00
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
let len = decoder.read_usize();
if len == 0 { LazyArray::default() } else { decoder.read_lazy_array(len) }
}
}
impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T> {
2022-01-18 13:22:50 +11:00
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
2023-07-10 10:45:24 -04:00
let width = decoder.read_usize();
2022-01-18 13:22:50 +11:00
let len = decoder.read_usize();
2023-07-10 10:45:24 -04:00
decoder.read_lazy_table(width, len)
}
}
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
2017-08-04 00:41:44 +03:00
impl MetadataBlob {
pub(crate) fn check_compatibility(
&self,
cfg_version: &'static str,
) -> Result<(), Option<String>> {
if !self.blob().starts_with(METADATA_HEADER) {
if self.blob().starts_with(b"rust") {
return Err(Some("<unknown rustc version>".to_owned()));
}
return Err(None);
}
let found_version =
LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
.decode(self);
if rustc_version(cfg_version) != found_version {
return Err(Some(found_version));
}
Ok(())
}
2024-01-29 23:59:09 +01:00
fn root_pos(&self) -> NonZero<usize> {
let offset = METADATA_HEADER.len();
let pos_bytes = self.blob()[offset..][..8].try_into().unwrap();
2023-11-26 20:45:56 -05:00
let pos = u64::from_le_bytes(pos_bytes);
NonZero::new(pos as usize).unwrap()
2023-11-26 20:45:56 -05:00
}
2023-11-26 20:45:56 -05:00
pub(crate) fn get_header(&self) -> CrateHeader {
let pos = self.root_pos();
LazyValue::<CrateHeader>::from_position(pos).decode(self)
}
pub(crate) fn get_root(&self) -> CrateRoot {
2023-11-26 20:45:56 -05:00
let pos = self.root_pos();
LazyValue::<CrateRoot>::from_position(pos).decode(self)
}
pub(crate) fn list_crate_metadata(
&self,
out: &mut dyn io::Write,
ls_kinds: &[String],
) -> io::Result<()> {
let root = self.get_root();
2023-09-10 14:32:58 +00:00
let all_ls_kinds = vec![
"root".to_owned(),
"lang_items".to_owned(),
"features".to_owned(),
"items".to_owned(),
];
let ls_kinds = if ls_kinds.contains(&"all".to_owned()) { &all_ls_kinds } else { ls_kinds };
for kind in ls_kinds {
match &**kind {
"root" => {
writeln!(out, "Crate info:")?;
writeln!(out, "name {}{}", root.name(), root.extra_filename)?;
writeln!(
out,
"hash {} stable_crate_id {:?}",
root.hash(),
root.stable_crate_id
)?;
writeln!(out, "proc_macro {:?}", root.proc_macro_data.is_some())?;
writeln!(out, "triple {}", root.header.triple.tuple())?;
writeln!(out, "edition {}", root.edition)?;
writeln!(out, "symbol_mangling_version {:?}", root.symbol_mangling_version)?;
writeln!(
out,
"required_panic_strategy {:?} panic_in_drop_strategy {:?}",
root.required_panic_strategy, root.panic_in_drop_strategy
)?;
writeln!(
out,
"has_global_allocator {} has_alloc_error_handler {} has_panic_handler {} has_default_lib_allocator {}",
root.has_global_allocator,
root.has_alloc_error_handler,
root.has_panic_handler,
root.has_default_lib_allocator
)?;
writeln!(
out,
"compiler_builtins {} needs_allocator {} needs_panic_runtime {} no_builtins {} panic_runtime {} profiler_runtime {}",
root.compiler_builtins,
root.needs_allocator,
root.needs_panic_runtime,
root.no_builtins,
root.panic_runtime,
root.profiler_runtime
)?;
2023-09-10 14:32:58 +00:00
writeln!(out, "=External Dependencies=")?;
let dylib_dependency_formats =
root.dylib_dependency_formats.decode(self).collect::<Vec<_>>();
for (i, dep) in root.crate_deps.decode(self).enumerate() {
let CrateDep { name, extra_filename, hash, host_hash, kind, is_private } =
dep;
let number = i + 1;
writeln!(
out,
"{number} {name}{extra_filename} hash {hash} host_hash {host_hash:?} kind {kind:?} {privacy}{linkage}",
privacy = if is_private { "private" } else { "public" },
linkage = if dylib_dependency_formats.is_empty() {
String::new()
} else {
format!(" linkage {:?}", dylib_dependency_formats[i])
}
)?;
}
write!(out, "\n")?;
2023-09-10 12:42:48 +00:00
}
"lang_items" => {
2023-09-10 14:32:58 +00:00
writeln!(out, "=Lang items=")?;
for (id, lang_item) in root.lang_items.decode(self) {
writeln!(
out,
"{} = crate{}",
lang_item.name(),
DefPath::make(LOCAL_CRATE, id, |parent| root
.tables
.def_keys
.get(self, parent)
.unwrap()
.decode(self))
.to_string_no_crate_verbose()
)?;
}
for lang_item in root.lang_items_missing.decode(self) {
writeln!(out, "{} = <missing>", lang_item.name())?;
}
write!(out, "\n")?;
}
"features" => {
2023-09-10 14:32:58 +00:00
writeln!(out, "=Lib features=")?;
for (feature, since) in root.lib_features.decode(self) {
writeln!(
out,
"{}{}",
feature,
if let FeatureStability::AcceptedSince(since) = since {
format!(" since {since}")
} else {
String::new()
}
)?;
}
write!(out, "\n")?;
}
2023-09-10 14:32:58 +00:00
"items" => {
writeln!(out, "=Items=")?;
fn print_item(
blob: &MetadataBlob,
out: &mut dyn io::Write,
item: DefIndex,
indent: usize,
) -> io::Result<()> {
let root = blob.get_root();
let def_kind = root.tables.def_kind.get(blob, item).unwrap();
2023-09-10 14:32:58 +00:00
let def_key = root.tables.def_keys.get(blob, item).unwrap().decode(blob);
2025-01-08 21:26:39 +01:00
#[allow(rustc::symbol_intern_string_literal)]
2023-09-10 14:32:58 +00:00
let def_name = if item == CRATE_DEF_INDEX {
kw::Crate
2023-09-10 14:32:58 +00:00
} else {
def_key
.disambiguated_data
.data
.get_opt_name()
.unwrap_or_else(|| Symbol::intern("???"))
};
let visibility =
root.tables.visibility.get(blob, item).unwrap().decode(blob).map_id(
|index| {
format!(
"crate{}",
DefPath::make(LOCAL_CRATE, index, |parent| root
.tables
.def_keys
.get(blob, parent)
.unwrap()
.decode(blob))
.to_string_no_crate_verbose()
)
},
);
write!(
out,
"{nil: <indent$}{:?} {:?} {} {{",
visibility,
def_kind,
def_name,
nil = "",
)?;
if let Some(children) =
root.tables.module_children_non_reexports.get(blob, item)
{
write!(out, "\n")?;
for child in children.decode(blob) {
print_item(blob, out, child, indent + 4)?;
}
writeln!(out, "{nil: <indent$}}}", nil = "")?;
} else {
writeln!(out, "}}")?;
}
Ok(())
}
print_item(self, out, CRATE_DEF_INDEX, 0)?;
write!(out, "\n")?;
}
_ => {
2023-09-10 14:32:58 +00:00
writeln!(
out,
2023-09-12 14:42:53 +00:00
"unknown -Zls kind. allowed values are: all, root, lang_items, features, items"
2023-09-10 14:32:58 +00:00
)?;
}
}
}
Ok(())
}
}
impl CrateRoot {
pub(crate) fn is_proc_macro_crate(&self) -> bool {
self.proc_macro_data.is_some()
}
pub(crate) fn name(&self) -> Symbol {
self.header.name
}
pub(crate) fn hash(&self) -> Svh {
self.header.hash
}
pub(crate) fn stable_crate_id(&self) -> StableCrateId {
self.stable_crate_id
}
pub(crate) fn decode_crate_deps<'a>(
&self,
metadata: &'a MetadataBlob,
) -> impl ExactSizeIterator<Item = CrateDep> {
self.crate_deps.decode(metadata)
}
pub(crate) fn decode_target_modifiers<'a>(
&self,
metadata: &'a MetadataBlob,
) -> impl ExactSizeIterator<Item = TargetModifier> {
self.target_modifiers.decode(metadata)
}
}
impl<'a> CrateMetadataRef<'a> {
fn missing(self, descr: &str, id: DefIndex) -> ! {
bug!("missing `{descr}` for {:?}", self.local_def_id(id))
}
fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
// with items in 'raw_proc_macros'.
let pos = self
.root
.proc_macro_data
.as_ref()
.unwrap()
.macros
.decode(self)
.position(|i| i == id)
.unwrap();
&self.raw_proc_macros.unwrap()[pos]
}
fn opt_item_name(self, item_index: DefIndex) -> Option<Symbol> {
let def_key = self.def_key(item_index);
def_key.disambiguated_data.data.get_opt_name().or_else(|| {
if def_key.disambiguated_data.data == DefPathData::Ctor {
let parent_index = def_key.parent.expect("no parent for a constructor");
self.def_key(parent_index).disambiguated_data.data.get_opt_name()
} else {
None
}
})
}
fn item_name(self, item_index: DefIndex) -> Symbol {
self.opt_item_name(item_index).expect("no encoded ident for item")
}
fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
let name = self.opt_item_name(item_index)?;
let span = self
.root
.tables
.def_ident_span
.get(self, item_index)
.unwrap_or_else(|| self.missing("def_ident_span", item_index))
.decode((self, sess));
Some(Ident::new(name, span))
}
fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident {
self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
}
2022-04-10 00:16:55 +02:00
#[inline]
pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum {
if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] }
}
fn def_kind(self, item_id: DefIndex) -> DefKind {
self.root
.tables
.def_kind
.get(self, item_id)
.unwrap_or_else(|| self.missing("def_kind", item_id))
}
fn get_span(self, index: DefIndex, sess: &Session) -> Span {
self.root
.tables
2022-02-17 21:33:23 +01:00
.def_span
.get(self, index)
.unwrap_or_else(|| self.missing("def_span", index))
.decode((self, sess))
}
fn load_proc_macro<'tcx>(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> SyntaxExtension {
let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let helper_attrs =
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(
trait_name,
SyntaxExtensionKind::Derive(Arc::new(DeriveProcMacro { client })),
helper_attrs,
)
}
ProcMacro::Attr { name, client } => {
(name, SyntaxExtensionKind::Attr(Arc::new(AttrProcMacro { client })), Vec::new())
}
ProcMacro::Bang { name, client } => {
(name, SyntaxExtensionKind::Bang(Arc::new(BangProcMacro { client })), Vec::new())
}
};
let sess = tcx.sess;
let attrs: Vec<_> = self.get_item_attrs(id, sess).collect();
SyntaxExtension::new(
sess,
kind,
self.get_span(id, sess),
helper_attrs,
self.root.edition,
Symbol::intern(name),
&attrs,
false,
)
}
fn get_variant(
self,
kind: DefKind,
index: DefIndex,
parent_did: DefId,
) -> (VariantIdx, ty::VariantDef) {
let adt_kind = match kind {
2022-07-03 18:02:35 +02:00
DefKind::Variant => ty::AdtKind::Enum,
DefKind::Struct => ty::AdtKind::Struct,
DefKind::Union => ty::AdtKind::Union,
_ => bug!(),
};
2022-06-08 20:59:59 +02:00
let data = self.root.tables.variant_data.get(self, index).unwrap().decode(self);
let variant_did =
if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None };
let ctor = data.ctor.map(|(kind, index)| (kind, self.local_def_id(index)));
(
data.idx,
ty::VariantDef::new(
self.item_name(index),
variant_did,
ctor,
data.discr,
self.get_associated_item_or_field_def_ids(index)
.map(|did| ty::FieldDef {
did,
name: self.item_name(did.index),
vis: self.get_visibility(did.index),
safety: self.get_safety(did.index),
2024-12-07 03:04:51 +00:00
value: self.get_default_field(did.index),
})
.collect(),
parent_did,
None,
data.is_non_exhaustive,
),
)
2016-10-23 08:32:37 +05:30
}
fn get_adt_def<'tcx>(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
2022-07-03 18:02:35 +02:00
let kind = self.def_kind(item_id);
let did = self.local_def_id(item_id);
2022-03-03 17:51:47 +01:00
let adt_kind = match kind {
2022-07-03 18:02:35 +02:00
DefKind::Enum => ty::AdtKind::Enum,
DefKind::Struct => ty::AdtKind::Struct,
DefKind::Union => ty::AdtKind::Union,
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
};
2022-03-03 17:51:47 +01:00
let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self);
let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind {
self.root
2020-03-30 17:06:00 +00:00
.tables
.module_children_non_reexports
.get(self, item_id)
.expect("variants are not encoded for an enum")
2016-10-23 08:32:37 +05:30
.decode(self)
.filter_map(|index| {
let kind = self.def_kind(index);
match kind {
DefKind::Ctor(..) => None,
_ => Some(self.get_variant(kind, index, did)),
}
})
2016-10-23 08:32:37 +05:30
.collect()
} else {
std::iter::once(self.get_variant(kind, item_id, did)).collect()
};
variants.sort_by_key(|(idx, _)| *idx);
tcx.mk_adt_def(
did,
adt_kind,
variants.into_iter().map(|(_, variant)| variant).collect(),
repr,
)
}
fn get_visibility(self, id: DefIndex) -> Visibility<DefId> {
self.root
.tables
.visibility
.get(self, id)
.unwrap_or_else(|| self.missing("visibility", id))
.decode(self)
.map_id(|index| self.local_def_id(index))
}
fn get_safety(self, id: DefIndex) -> Safety {
self.root.tables.safety.get(self, id).unwrap_or_else(|| self.missing("safety", id))
}
2024-12-07 03:04:51 +00:00
fn get_default_field(self, id: DefIndex) -> Option<DefId> {
self.root.tables.default_fields.get(self, id).map(|d| d.decode(self))
}
fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
}
fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
self.root
.tables
.expn_that_defined
.get(self, id)
.unwrap_or_else(|| self.missing("expn_that_defined", id))
.decode((self, sess))
}
fn get_debugger_visualizers(self) -> Vec<DebuggerVisualizerFile> {
self.root.debugger_visualizers.decode(self).collect::<Vec<_>>()
}
/// Iterates over all the stability attributes in the given crate.
2023-11-17 23:40:04 +00:00
fn get_lib_features(self) -> LibFeatures {
LibFeatures {
stability: self
.root
.lib_features
.decode(self)
.map(|(sym, stab)| (sym, (stab, DUMMY_SP)))
.collect(),
}
}
/// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute
/// has an `implied_by` meta item, then the mapping from the implied feature to the actual
/// feature is a stability implication).
fn get_stability_implications<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] {
tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self))
}
/// Iterates over the lang items in the given crate.
fn get_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] {
2022-03-18 17:02:32 +01:00
tcx.arena.alloc_from_iter(
self.root
.lang_items
.decode(self)
.map(move |(def_index, index)| (self.local_def_id(def_index), index)),
)
}
fn get_stripped_cfg_items<'tcx>(
self,
cnum: CrateNum,
tcx: TyCtxt<'tcx>,
) -> &'tcx [StrippedCfgItem] {
let item_names = self
.root
.stripped_cfg_items
.decode((self, tcx))
.map(|item| item.map_mod_id(|index| DefId { krate: cnum, index }));
tcx.arena.alloc_from_iter(item_names)
}
/// Iterates over the diagnostic items in the given crate.
fn get_diagnostic_items(self) -> DiagnosticItems {
let mut id_to_name = DefIdMap::default();
let name_to_id = self
.root
.diagnostic_items
.decode(self)
.map(|(name, def_index)| {
let id = self.local_def_id(def_index);
id_to_name.insert(id, name);
(name, id)
})
.collect();
DiagnosticItems { id_to_name, name_to_id }
}
fn get_mod_child(self, id: DefIndex, sess: &Session) -> ModChild {
let ident = self.item_ident(id, sess);
let res = Res::Def(self.def_kind(id), self.local_def_id(id));
let vis = self.get_visibility(id);
ModChild { ident, res, vis, reexport_chain: Default::default() }
}
/// Iterates over all named children of the given module,
/// including both proper items and reexports.
/// Module here is understood in name resolution sense - it can be a `mod` item,
/// or a crate root, or an enum, or a trait.
fn get_module_children(
self,
id: DefIndex,
sess: &'a Session,
) -> impl Iterator<Item = ModChild> {
iter::from_coroutine(
2024-04-29 09:27:34 -04:00
#[coroutine]
move || {
if let Some(data) = &self.root.proc_macro_data {
// If we are loading as a proc macro, we want to return
// the view of this crate as a proc macro crate.
if id == CRATE_DEF_INDEX {
for child_index in data.macros.decode(self) {
yield self.get_mod_child(child_index, sess);
}
}
} else {
// Iterate over all children.
let non_reexports =
self.root.tables.module_children_non_reexports.get(self, id);
for child_index in non_reexports.unwrap().decode(self) {
yield self.get_mod_child(child_index, sess);
}
let reexports = self.root.tables.module_children_reexports.get(self, id);
if !reexports.is_default() {
for reexport in reexports.decode((self, sess)) {
yield reexport;
}
2022-06-08 21:38:04 +02:00
}
}
},
)
}
fn is_ctfe_mir_available(self, id: DefIndex) -> bool {
self.root.tables.mir_for_ctfe.get(self, id).is_some()
}
fn is_item_mir_available(self, id: DefIndex) -> bool {
2022-02-17 21:33:23 +01:00
self.root.tables.optimized_mir.get(self, id).is_some()
}
2022-08-04 22:03:16 +02:00
fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
self.root
.tables
.fn_arg_names
.get(self, id)
.expect("argument names not encoded for a function")
2022-08-04 22:03:16 +02:00
.decode((self, sess))
.nth(0)
.is_some_and(|ident| ident.name == kw::SelfLower)
}
fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator<Item = DefId> {
self.root
.tables
.associated_item_or_field_def_ids
.get(self, id)
.unwrap_or_else(|| self.missing("associated_item_or_field_def_ids", id))
.decode(self)
.map(move |child_index| self.local_def_id(child_index))
}
2022-08-04 22:03:16 +02:00
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() {
kw::Empty
} else {
self.item_name(id)
};
let (kind, has_self) = match self.def_kind(id) {
DefKind::AssocConst => (ty::AssocKind::Const, false),
DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
DefKind::AssocTy => (ty::AssocKind::Type, false),
_ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
};
let container = self.root.tables.assoc_container.get(self, id).unwrap();
let opt_rpitit_info =
self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self));
ty::AssocItem {
name,
kind,
def_id: self.local_def_id(id),
trait_item_def_id: self.get_trait_item_def_id(id),
2022-03-13 00:52:25 +01:00
container,
fn_has_self_parameter: has_self,
opt_rpitit_info,
}
}
fn get_ctor(self, node_id: DefIndex) -> Option<(CtorKind, DefId)> {
2022-07-03 18:02:35 +02:00
match self.def_kind(node_id) {
DefKind::Struct | DefKind::Variant => {
2022-06-08 20:59:59 +02:00
let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self);
vdata.ctor.map(|(kind, index)| (kind, self.local_def_id(index)))
}
2016-10-23 08:32:37 +05:30
_ => None,
}
}
fn get_item_attrs(
self,
id: DefIndex,
sess: &'a Session,
) -> impl Iterator<Item = hir::Attribute> {
2020-03-14 17:37:34 +01:00
self.root
.tables
.attributes
.get(self, id)
.unwrap_or_else(|| {
// Structure and variant constructors don't have any attributes encoded for them,
// but we assume that someone passing a constructor ID actually wants to look at
// the attributes on the corresponding struct or variant.
let def_key = self.def_key(id);
assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor);
let parent_id = def_key.parent.expect("no parent for a constructor");
self.root
.tables
.attributes
.get(self, parent_id)
.expect("no encoded attributes for a structure or variant")
})
2020-03-14 17:37:34 +01:00
.decode((self, sess))
}
fn get_inherent_implementations_for_type<'tcx>(
self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxt<'tcx>,
id: DefIndex,
2018-11-30 15:19:12 +01:00
) -> &'tcx [DefId] {
tcx.arena.alloc_from_iter(
self.root
2020-03-30 17:06:00 +00:00
.tables
.inherent_impls
.get(self, id)
.decode(self)
.map(|index| self.local_def_id(index)),
)
}
/// Decodes all traits in the crate (for rustdoc and rustc diagnostics).
fn get_traits(self) -> impl Iterator<Item = DefId> {
self.root.traits.decode(self).map(move |index| self.local_def_id(index))
}
/// Decodes all trait impls in the crate (for rustdoc).
fn get_trait_impls(self) -> impl Iterator<Item = DefId> {
self.cdata.trait_impls.values().flat_map(move |impls| {
impls.decode(self).map(move |(impl_index, _)| self.local_def_id(impl_index))
})
}
fn get_incoherent_impls<'tcx>(self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] {
if let Some(impls) = self.cdata.incoherent_impls.get(&simp) {
tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx)))
} else {
&[]
}
}
fn get_implementations_of_trait<'tcx>(
self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
) -> &'tcx [(DefId, Option<SimplifiedType>)] {
if self.trait_impls.is_empty() {
return &[];
}
// Do a reverse lookup beforehand to avoid touching the crate_num
// hash map in the loop below.
let key = match self.reverse_translate_def_id(trait_def_id) {
Some(def_id) => (def_id.krate.as_u32(), def_id.index),
None => return &[],
};
if let Some(impls) = self.trait_impls.get(&key) {
tcx.arena.alloc_from_iter(
impls
.decode(self)
.map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)),
)
} else {
&[]
}
}
fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> {
self.root.native_libraries.decode((self, sess))
}
fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span {
Implement span quoting for proc-macros This PR implements span quoting, allowing proc-macros to produce spans pointing *into their own crate*. This is used by the unstable `proc_macro::quote!` macro, allowing us to get error messages like this: ``` error[E0412]: cannot find type `MissingType` in this scope --> $DIR/auxiliary/span-from-proc-macro.rs:37:20 | LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream { | ----------------------------------------------------------------------------------- in this expansion of procedural macro `#[error_from_attribute]` ... LL | field: MissingType | ^^^^^^^^^^^ not found in this scope | ::: $DIR/span-from-proc-macro.rs:8:1 | LL | #[error_from_attribute] | ----------------------- in this macro invocation ``` Here, `MissingType` occurs inside the implementation of the proc-macro `#[error_from_attribute]`. Previosuly, this would always result in a span pointing at `#[error_from_attribute]` This will make many proc-macro-related error message much more useful - when a proc-macro generates code containing an error, users will get an error message pointing directly at that code (within the macro definition), instead of always getting a span pointing at the macro invocation site. This is implemented as follows: * When a proc-macro crate is being *compiled*, it causes the `quote!` macro to get run. This saves all of the sapns in the input to `quote!` into the metadata of *the proc-macro-crate* (which we are currently compiling). The `quote!` macro then expands to a call to `proc_macro::Span::recover_proc_macro_span(id)`, where `id` is an opaque identifier for the span in the crate metadata. * When the same proc-macro crate is *run* (e.g. it is loaded from disk and invoked by some consumer crate), the call to `proc_macro::Span::recover_proc_macro_span` causes us to load the span from the proc-macro crate's metadata. The proc-macro then produces a `TokenStream` containing a `Span` pointing into the proc-macro crate itself. The recursive nature of 'quote!' can be difficult to understand at first. The file `src/test/ui/proc-macro/quote-debug.stdout` shows the output of the `quote!` macro, which should make this eaier to understand. This PR also supports custom quoting spans in custom quote macros (e.g. the `quote` crate). All span quoting goes through the `proc_macro::quote_span` method, which can be called by a custom quote macro to perform span quoting. An example of this usage is provided in `src/test/ui/proc-macro/auxiliary/custom-quote.rs` Custom quoting currently has a few limitations: In order to quote a span, we need to generate a call to `proc_macro::Span::recover_proc_macro_span`. However, proc-macros support renaming the `proc_macro` crate, so we can't simply hardcode this path. Previously, the `quote_span` method used the path `crate::Span` - however, this only works when it is called by the builtin `quote!` macro in the same crate. To support being called from arbitrary crates, we need access to the name of the `proc_macro` crate to generate a path. This PR adds an additional argument to `quote_span` to specify the name of the `proc_macro` crate. Howver, this feels kind of hacky, and we may want to change this before stabilizing anything quote-related. Additionally, using `quote_span` currently requires enabling the `proc_macro_internals` feature. The builtin `quote!` macro has an `#[allow_internal_unstable]` attribute, but this won't work for custom quote implementations. This will likely require some additional tricks to apply `allow_internal_unstable` to the span of `proc_macro::Span::recover_proc_macro_span`.
2020-08-02 19:52:16 -04:00
self.root
.tables
.proc_macro_quoted_spans
.get(self, index)
.unwrap_or_else(|| panic!("Missing proc macro quoted span: {index:?}"))
Implement span quoting for proc-macros This PR implements span quoting, allowing proc-macros to produce spans pointing *into their own crate*. This is used by the unstable `proc_macro::quote!` macro, allowing us to get error messages like this: ``` error[E0412]: cannot find type `MissingType` in this scope --> $DIR/auxiliary/span-from-proc-macro.rs:37:20 | LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream { | ----------------------------------------------------------------------------------- in this expansion of procedural macro `#[error_from_attribute]` ... LL | field: MissingType | ^^^^^^^^^^^ not found in this scope | ::: $DIR/span-from-proc-macro.rs:8:1 | LL | #[error_from_attribute] | ----------------------- in this macro invocation ``` Here, `MissingType` occurs inside the implementation of the proc-macro `#[error_from_attribute]`. Previosuly, this would always result in a span pointing at `#[error_from_attribute]` This will make many proc-macro-related error message much more useful - when a proc-macro generates code containing an error, users will get an error message pointing directly at that code (within the macro definition), instead of always getting a span pointing at the macro invocation site. This is implemented as follows: * When a proc-macro crate is being *compiled*, it causes the `quote!` macro to get run. This saves all of the sapns in the input to `quote!` into the metadata of *the proc-macro-crate* (which we are currently compiling). The `quote!` macro then expands to a call to `proc_macro::Span::recover_proc_macro_span(id)`, where `id` is an opaque identifier for the span in the crate metadata. * When the same proc-macro crate is *run* (e.g. it is loaded from disk and invoked by some consumer crate), the call to `proc_macro::Span::recover_proc_macro_span` causes us to load the span from the proc-macro crate's metadata. The proc-macro then produces a `TokenStream` containing a `Span` pointing into the proc-macro crate itself. The recursive nature of 'quote!' can be difficult to understand at first. The file `src/test/ui/proc-macro/quote-debug.stdout` shows the output of the `quote!` macro, which should make this eaier to understand. This PR also supports custom quoting spans in custom quote macros (e.g. the `quote` crate). All span quoting goes through the `proc_macro::quote_span` method, which can be called by a custom quote macro to perform span quoting. An example of this usage is provided in `src/test/ui/proc-macro/auxiliary/custom-quote.rs` Custom quoting currently has a few limitations: In order to quote a span, we need to generate a call to `proc_macro::Span::recover_proc_macro_span`. However, proc-macros support renaming the `proc_macro` crate, so we can't simply hardcode this path. Previously, the `quote_span` method used the path `crate::Span` - however, this only works when it is called by the builtin `quote!` macro in the same crate. To support being called from arbitrary crates, we need access to the name of the `proc_macro` crate to generate a path. This PR adds an additional argument to `quote_span` to specify the name of the `proc_macro` crate. Howver, this feels kind of hacky, and we may want to change this before stabilizing anything quote-related. Additionally, using `quote_span` currently requires enabling the `proc_macro_internals` feature. The builtin `quote!` macro has an `#[allow_internal_unstable]` attribute, but this won't work for custom quote implementations. This will likely require some additional tricks to apply `allow_internal_unstable` to the span of `proc_macro::Span::recover_proc_macro_span`.
2020-08-02 19:52:16 -04:00
.decode((self, sess))
}
fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> {
self.root.foreign_modules.decode((self, sess))
rustc: Add a `#[wasm_import_module]` attribute This commit adds a new attribute to the Rust compiler specific to the wasm target (and no other targets). The `#[wasm_import_module]` attribute is used to specify the module that a name is imported from, and is used like so: #[wasm_import_module = "./foo.js"] extern { fn some_js_function(); } Here the import of the symbol `some_js_function` is tagged with the `./foo.js` module in the wasm output file. Wasm-the-format includes two fields on all imports, a module and a field. The field is the symbol name (`some_js_function` above) and the module has historically unconditionally been `"env"`. I'm not sure if this `"env"` convention has asm.js or LLVM roots, but regardless we'd like the ability to configure it! The proposed ES module integration with wasm (aka a wasm module is "just another ES module") requires that the import module of wasm imports is interpreted as an ES module import, meaning that you'll need to encode paths, NPM packages, etc. As a result, we'll need this to be something other than `"env"`! Unfortunately neither our version of LLVM nor LLD supports custom import modules (aka anything not `"env"`). My hope is that by the time LLVM 7 is released both will have support, but in the meantime this commit adds some primitive encoding/decoding of wasm files to the compiler. This way rustc postprocesses the wasm module that LLVM emits to ensure it's got all the imports we'd like to have in it. Eventually I'd ideally like to unconditionally require this attribute to be placed on all `extern { ... }` blocks. For now though it seemed prudent to add it as an unstable attribute, so for now it's not required (as that'd force usage of a feature gate). Hopefully it doesn't take too long to "stabilize" this! cc rust-lang-nursery/rust-wasm#29
2018-02-10 14:28:17 -08:00
}
fn get_dylib_dependency_formats<'tcx>(
self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxt<'tcx>,
) -> &'tcx [(CrateNum, LinkagePreference)] {
tcx.arena.alloc_from_iter(
2016-10-23 08:32:37 +05:30
self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| {
2024-12-12 14:55:36 +00:00
let cnum = CrateNum::new(i + 1); // We skipped LOCAL_CRATE when encoding
link.map(|link| (self.cnum_map[cnum], link))
}),
)
}
fn get_missing_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] {
tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
}
fn exported_symbols<'tcx>(
self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
}
fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef {
2022-07-03 18:02:35 +02:00
match self.def_kind(id) {
DefKind::Macro(_) => {
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) }
}
2016-10-28 06:52:45 +00:00
_ => bug!(),
}
}
#[inline]
fn def_key(self, index: DefIndex) -> DefKey {
*self
.def_key_cache
.lock()
.entry(index)
.or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self))
}
// Returns the path leading to the thing with this `id`.
fn def_path(self, id: DefIndex) -> DefPath {
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
}
#[inline]
fn def_path_hash(self, index: DefIndex) -> DefPathHash {
// This is a hack to workaround the fact that we can't easily encode/decode a Hash64
// into the FixedSizeEncoding, as Hash64 lacks a Default impl. A future refactor to
// relax the Default restriction will likely fix this.
let fingerprint = Fingerprint::new(
self.root.stable_crate_id.as_u64(),
self.root.tables.def_path_hashes.get(self, index),
);
DefPathHash::new(self.root.stable_crate_id, fingerprint.split().1)
}
#[inline]
fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex {
self.def_path_hash_map.def_path_hash_to_def_index(&hash)
}
fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
debug_assert_eq!(ExpnId::from_hash(hash), None);
let index_guess = ExpnIndex::from_u32(index_guess);
let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self));
let index = if old_hash == Some(hash) {
// Fast path: the expn and its index is unchanged from the
// previous compilation session. There is no need to decode anything
// else.
index_guess
} else {
// Slow path: We need to find out the new `DefIndex` of the provided
// `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
// stored in this crate.
let map = self.cdata.expn_hash_map.get_or_init(|| {
let end_id = self.root.expn_hashes.size() as u32;
let mut map =
UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default());
for i in 0..end_id {
let i = ExpnIndex::from_u32(i);
if let Some(hash) = self.root.expn_hashes.get(self, i) {
map.insert(hash.decode(self), i);
}
}
map
});
map[&hash]
};
2021-10-02 17:35:27 +02:00
let data = self.root.expn_data.get(self, index).unwrap().decode((self, sess));
2021-06-27 20:06:26 +02:00
rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash)
}
2018-08-18 12:14:14 +02:00
/// Imports the source_map from an external crate into the source_map of the crate
/// currently being compiled (the "local crate").
///
/// The import algorithm works analogous to how AST items are inlined from an
/// external crate's metadata:
2018-08-18 12:14:14 +02:00
/// For every SourceFile in the external source_map an 'inline' copy is created in the
/// local source_map. The correspondence relation between external and local
2018-08-18 12:13:52 +02:00
/// SourceFiles is recorded in the `ImportedSourceFile` objects returned from this
/// function. When an item from an external crate is later inlined into this
/// crate, this correspondence information is used to translate the span
/// information of the inlined item so that it refers the correct positions in
2018-08-18 12:14:14 +02:00
/// the local source_map (see `<decoder::DecodeContext as SpecializedDecoder<Span>>`).
///
2018-08-18 12:13:52 +02:00
/// The import algorithm in the function below will reuse SourceFiles already
2018-08-18 12:14:14 +02:00
/// existing in the local source_map. For example, even if the SourceFile of some
/// source file of libstd gets imported many times, there will only ever be
2018-08-18 12:14:14 +02:00
/// one SourceFile object for the corresponding file in the local source_map.
///
2018-08-18 12:13:52 +02:00
/// Note that imported SourceFiles do not actually contain the source code of the
/// file they represent, just information about length, line breaks, and
/// multibyte characters. This information is enough to generate valid debuginfo
/// for items inlined from other crates.
///
/// Proc macro crates don't currently export spans, so this function does not have
/// to work for them.
2022-08-06 23:00:49 +02:00
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*.
sess.opts.real_rust_source_base_dir.is_some()
// Some tests need the translation to be always skipped.
&& sess.opts.unstable_opts.translate_remapped_path_to_local_path
})
.filter(|virtual_dir| {
// Don't translate away `/rustc/$hash` if we're still remapping to it,
// since that means we're still building `std`/`rustc` that need it,
// and we don't want the real path to leak into codegen/debuginfo.
!sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir)
})
}
let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| {
// Translate the virtual `/rustc/$hash` prefix back to a real directory
// that should hold actual sources, where possible.
//
// NOTE: if you update this, you might need to also update bootstrap's code for generating
// the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
let virtual_rust_source_base_dir = [
filter(sess, option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(Path::new)),
filter(sess, sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref()),
];
debug!(
"try_to_translate_virtual_to_real(name={:?}): \
virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}",
name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
);
for virtual_dir in virtual_rust_source_base_dir.iter().flatten() {
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir
&& let rustc_span::FileName::Real(old_name) = name
&& let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
old_name
&& let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
{
// The std library crates are in
// `$sysroot/lib/rustlib/src/rust/library`, whereas other crates
// may be in `$sysroot/lib/rustlib/src/rust/` directly. So we
// detect crates from the std libs and handle them specially.
const STD_LIBS: &[&str] = &[
"core",
"alloc",
"std",
"test",
"term",
"unwind",
"proc_macro",
"panic_abort",
"panic_unwind",
"profiler_builtins",
"rtstartup",
"rustc-std-workspace-core",
"rustc-std-workspace-alloc",
"rustc-std-workspace-std",
"backtrace",
];
let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l));
let new_path = if is_std_lib {
real_dir.join("library").join(rest)
} else {
real_dir.join(rest)
};
debug!(
"try_to_translate_virtual_to_real: `{}` -> `{}`",
virtual_name.display(),
new_path.display(),
);
// Check if the translated real path is affected by any user-requested
// remaps via --remap-path-prefix. Apply them if so.
// Note that this is a special case for imported rust-src paths specified by
// https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
// Other imported paths are not currently remapped (see #66251).
let (user_remapped, applied) =
sess.source_map().path_mapping().map_prefix(&new_path);
let new_name = if applied {
rustc_span::RealFileName::Remapped {
local_path: Some(new_path.clone()),
virtual_name: user_remapped.to_path_buf(),
}
} else {
rustc_span::RealFileName::LocalPath(new_path)
};
*old_name = new_name;
}
}
};
2022-08-06 23:27:45 +02:00
let mut import_info = self.cdata.source_map_import_info.lock();
2022-08-06 23:00:49 +02:00
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 original_end_pos = source_file_to_import.end_position();
2022-08-06 23:00:49 +02:00
let rustc_span::SourceFile {
mut name,
src_hash,
checksum_hash,
start_pos: original_start_pos,
source_len,
2022-08-06 23:00:49 +02:00
lines,
multibyte_chars,
normalized_pos,
stable_id,
2022-08-06 23:00:49 +02:00
..
} = source_file_to_import;
Apply `simulate-remapped-rust-src-base` even `remap-debuginfo` is set in config.toml This is really a mess. Here is the situation before this change: - UI tests depend on not having `rust-src` available. In particular, <https://github.com/rust-lang/rust/blob/3f374128ee3924514aacadf96479e17fee8f9903/tests/ui/tuple/wrong_argument_ice.stderr#L7-L8> is depending on the `note` being a single line and not showing the source code. - When `download-rustc` is disabled, we pass `-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX` `-Ztranslate-remapped-path-to-local-path=no`, which changes the diagnostic to something like ` --> /rustc/FAKE_PREFIX/library/alloc/src/collections/vec_deque/mod.rs:1657:12` - When `download-rustc` is enabled, we still pass those flags, but they no longer have an effect. Instead rustc emits diagnostic paths like this: ` --> /rustc/39c6804b92aa202369e402525cee329556bc1db0/library/alloc/src/collections/vec_deque/mod.rs:1657:12`. Notice how there's a real commit and not `FAKE_PREFIX`. This happens because we set `CFG_VIRTUAL_RUST_SOURCE_BASE_DIR` during bootstrapping for CI artifacts, and rustc previously didn't allow for `simulate-remapped` to affect paths that had already been remapped. - Pietro noticed this and decided the right thing was to normalize `/rustc/<commit>` to `$SRC_DIR` in compiletest: https://github.com/rust-lang/rust/pull/103969/commits/470423c3d2cde3a62d5d4ac23840d734e8145366 - After my change to `x test core`, which rebuilds stage 2 std from source so `build/stage2-std` and `build/stage2` use the same `.rlib` metadata, the compiler suddenly notices it has sources for `std` available and prints those in the diagnostic, causing the test to fail. This changes `simulate-remapped-rust-src-base` to support remapping paths that have already been remapped, unblocking download-rustc. Unfortunately, although this fixes the specific problem for download-rustc, it doesn't seem to affect all the compiler's diagnostics. In particular, various `mir-opt` tests are failing to respect `simulate-remapped-path-prefix` (I looked into fixing this but it seems non-trivial). As a result, we can't remove the normalization in compiletest that maps `/rustc/<commit>` to `$SRC_DIR`, so this change is currently untested anywhere except locally.
2023-04-22 14:24:32 -05:00
// If this file is under $sysroot/lib/rustlib/src/
// and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base,
2022-08-06 23:00:49 +02:00
// 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
&& let Some(real_dir) = &sess.opts.real_rust_source_base_dir
Apply `simulate-remapped-rust-src-base` even `remap-debuginfo` is set in config.toml This is really a mess. Here is the situation before this change: - UI tests depend on not having `rust-src` available. In particular, <https://github.com/rust-lang/rust/blob/3f374128ee3924514aacadf96479e17fee8f9903/tests/ui/tuple/wrong_argument_ice.stderr#L7-L8> is depending on the `note` being a single line and not showing the source code. - When `download-rustc` is disabled, we pass `-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX` `-Ztranslate-remapped-path-to-local-path=no`, which changes the diagnostic to something like ` --> /rustc/FAKE_PREFIX/library/alloc/src/collections/vec_deque/mod.rs:1657:12` - When `download-rustc` is enabled, we still pass those flags, but they no longer have an effect. Instead rustc emits diagnostic paths like this: ` --> /rustc/39c6804b92aa202369e402525cee329556bc1db0/library/alloc/src/collections/vec_deque/mod.rs:1657:12`. Notice how there's a real commit and not `FAKE_PREFIX`. This happens because we set `CFG_VIRTUAL_RUST_SOURCE_BASE_DIR` during bootstrapping for CI artifacts, and rustc previously didn't allow for `simulate-remapped` to affect paths that had already been remapped. - Pietro noticed this and decided the right thing was to normalize `/rustc/<commit>` to `$SRC_DIR` in compiletest: https://github.com/rust-lang/rust/pull/103969/commits/470423c3d2cde3a62d5d4ac23840d734e8145366 - After my change to `x test core`, which rebuilds stage 2 std from source so `build/stage2-std` and `build/stage2` use the same `.rlib` metadata, the compiler suddenly notices it has sources for `std` available and prints those in the diagnostic, causing the test to fail. This changes `simulate-remapped-rust-src-base` to support remapping paths that have already been remapped, unblocking download-rustc. Unfortunately, although this fixes the specific problem for download-rustc, it doesn't seem to affect all the compiler's diagnostics. In particular, various `mir-opt` tests are failing to respect `simulate-remapped-path-prefix` (I looked into fixing this but it seems non-trivial). As a result, we can't remove the normalization in compiletest that maps `/rustc/<commit>` to `$SRC_DIR`, so this change is currently untested anywhere except locally.
2023-04-22 14:24:32 -05:00
&& let rustc_span::FileName::Real(ref mut old_name) = name
{
let relative_path = match old_name {
rustc_span::RealFileName::LocalPath(local) => {
local.strip_prefix(real_dir).ok()
2023-10-13 08:58:33 +00:00
}
Apply `simulate-remapped-rust-src-base` even `remap-debuginfo` is set in config.toml This is really a mess. Here is the situation before this change: - UI tests depend on not having `rust-src` available. In particular, <https://github.com/rust-lang/rust/blob/3f374128ee3924514aacadf96479e17fee8f9903/tests/ui/tuple/wrong_argument_ice.stderr#L7-L8> is depending on the `note` being a single line and not showing the source code. - When `download-rustc` is disabled, we pass `-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX` `-Ztranslate-remapped-path-to-local-path=no`, which changes the diagnostic to something like ` --> /rustc/FAKE_PREFIX/library/alloc/src/collections/vec_deque/mod.rs:1657:12` - When `download-rustc` is enabled, we still pass those flags, but they no longer have an effect. Instead rustc emits diagnostic paths like this: ` --> /rustc/39c6804b92aa202369e402525cee329556bc1db0/library/alloc/src/collections/vec_deque/mod.rs:1657:12`. Notice how there's a real commit and not `FAKE_PREFIX`. This happens because we set `CFG_VIRTUAL_RUST_SOURCE_BASE_DIR` during bootstrapping for CI artifacts, and rustc previously didn't allow for `simulate-remapped` to affect paths that had already been remapped. - Pietro noticed this and decided the right thing was to normalize `/rustc/<commit>` to `$SRC_DIR` in compiletest: https://github.com/rust-lang/rust/pull/103969/commits/470423c3d2cde3a62d5d4ac23840d734e8145366 - After my change to `x test core`, which rebuilds stage 2 std from source so `build/stage2-std` and `build/stage2` use the same `.rlib` metadata, the compiler suddenly notices it has sources for `std` available and prints those in the diagnostic, causing the test to fail. This changes `simulate-remapped-rust-src-base` to support remapping paths that have already been remapped, unblocking download-rustc. Unfortunately, although this fixes the specific problem for download-rustc, it doesn't seem to affect all the compiler's diagnostics. In particular, various `mir-opt` tests are failing to respect `simulate-remapped-path-prefix` (I looked into fixing this but it seems non-trivial). As a result, we can't remove the normalization in compiletest that maps `/rustc/<commit>` to `$SRC_DIR`, so this change is currently untested anywhere except locally.
2023-04-22 14:24:32 -05:00
rustc_span::RealFileName::Remapped { virtual_name, .. } => {
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR")
.and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
}
};
debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base");
for subdir in ["library", "compiler"] {
Apply `simulate-remapped-rust-src-base` even `remap-debuginfo` is set in config.toml This is really a mess. Here is the situation before this change: - UI tests depend on not having `rust-src` available. In particular, <https://github.com/rust-lang/rust/blob/3f374128ee3924514aacadf96479e17fee8f9903/tests/ui/tuple/wrong_argument_ice.stderr#L7-L8> is depending on the `note` being a single line and not showing the source code. - When `download-rustc` is disabled, we pass `-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX` `-Ztranslate-remapped-path-to-local-path=no`, which changes the diagnostic to something like ` --> /rustc/FAKE_PREFIX/library/alloc/src/collections/vec_deque/mod.rs:1657:12` - When `download-rustc` is enabled, we still pass those flags, but they no longer have an effect. Instead rustc emits diagnostic paths like this: ` --> /rustc/39c6804b92aa202369e402525cee329556bc1db0/library/alloc/src/collections/vec_deque/mod.rs:1657:12`. Notice how there's a real commit and not `FAKE_PREFIX`. This happens because we set `CFG_VIRTUAL_RUST_SOURCE_BASE_DIR` during bootstrapping for CI artifacts, and rustc previously didn't allow for `simulate-remapped` to affect paths that had already been remapped. - Pietro noticed this and decided the right thing was to normalize `/rustc/<commit>` to `$SRC_DIR` in compiletest: https://github.com/rust-lang/rust/pull/103969/commits/470423c3d2cde3a62d5d4ac23840d734e8145366 - After my change to `x test core`, which rebuilds stage 2 std from source so `build/stage2-std` and `build/stage2` use the same `.rlib` metadata, the compiler suddenly notices it has sources for `std` available and prints those in the diagnostic, causing the test to fail. This changes `simulate-remapped-rust-src-base` to support remapping paths that have already been remapped, unblocking download-rustc. Unfortunately, although this fixes the specific problem for download-rustc, it doesn't seem to affect all the compiler's diagnostics. In particular, various `mir-opt` tests are failing to respect `simulate-remapped-path-prefix` (I looked into fixing this but it seems non-trivial). As a result, we can't remove the normalization in compiletest that maps `/rustc/<commit>` to `$SRC_DIR`, so this change is currently untested anywhere except locally.
2023-04-22 14:24:32 -05:00
if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok())
{
*old_name = rustc_span::RealFileName::Remapped {
Apply `simulate-remapped-rust-src-base` even `remap-debuginfo` is set in config.toml This is really a mess. Here is the situation before this change: - UI tests depend on not having `rust-src` available. In particular, <https://github.com/rust-lang/rust/blob/3f374128ee3924514aacadf96479e17fee8f9903/tests/ui/tuple/wrong_argument_ice.stderr#L7-L8> is depending on the `note` being a single line and not showing the source code. - When `download-rustc` is disabled, we pass `-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX` `-Ztranslate-remapped-path-to-local-path=no`, which changes the diagnostic to something like ` --> /rustc/FAKE_PREFIX/library/alloc/src/collections/vec_deque/mod.rs:1657:12` - When `download-rustc` is enabled, we still pass those flags, but they no longer have an effect. Instead rustc emits diagnostic paths like this: ` --> /rustc/39c6804b92aa202369e402525cee329556bc1db0/library/alloc/src/collections/vec_deque/mod.rs:1657:12`. Notice how there's a real commit and not `FAKE_PREFIX`. This happens because we set `CFG_VIRTUAL_RUST_SOURCE_BASE_DIR` during bootstrapping for CI artifacts, and rustc previously didn't allow for `simulate-remapped` to affect paths that had already been remapped. - Pietro noticed this and decided the right thing was to normalize `/rustc/<commit>` to `$SRC_DIR` in compiletest: https://github.com/rust-lang/rust/pull/103969/commits/470423c3d2cde3a62d5d4ac23840d734e8145366 - After my change to `x test core`, which rebuilds stage 2 std from source so `build/stage2-std` and `build/stage2` use the same `.rlib` metadata, the compiler suddenly notices it has sources for `std` available and prints those in the diagnostic, causing the test to fail. This changes `simulate-remapped-rust-src-base` to support remapping paths that have already been remapped, unblocking download-rustc. Unfortunately, although this fixes the specific problem for download-rustc, it doesn't seem to affect all the compiler's diagnostics. In particular, various `mir-opt` tests are failing to respect `simulate-remapped-path-prefix` (I looked into fixing this but it seems non-trivial). As a result, we can't remove the normalization in compiletest that maps `/rustc/<commit>` to `$SRC_DIR`, so this change is currently untested anywhere except locally.
2023-04-22 14:24:32 -05:00
local_path: None, // FIXME: maybe we should preserve this?
virtual_name: virtual_dir.join(subdir).join(rest),
};
break;
}
}
2022-08-06 23:00:49 +02:00
}
2022-08-06 23:00:49 +02:00
// 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 local_version = sess.source_map().new_imported_source_file(
name,
src_hash,
checksum_hash,
stable_id,
source_len.to_u32(),
2022-08-06 23:00:49 +02:00
self.cnum,
lines,
multibyte_chars,
normalized_pos,
source_file_index,
);
debug!(
"CrateMetaData::imported_source_files alloc \
source_file {:?} original (start_pos {:?} source_len {:?}) \
translated (start_pos {:?} source_len {:?})",
2022-08-06 23:00:49 +02:00
local_version.name,
original_start_pos,
source_len,
2022-08-06 23:00:49 +02:00
local_version.start_pos,
local_version.source_len
2022-08-06 23:00:49 +02:00
);
2022-08-06 23:00:49 +02:00
ImportedSourceFile {
original_start_pos,
original_end_pos,
2022-08-06 23:00:49 +02:00
translated_source_file: local_version,
}
})
.clone()
}
fn get_attr_flags(self, index: DefIndex) -> AttrFlags {
self.root.tables.attr_flags.get(self, index)
}
fn get_intrinsic(self, index: DefIndex) -> Option<ty::IntrinsicDef> {
self.root.tables.intrinsic.get(self, index).map(|d| d.decode(self))
}
fn get_doc_link_resolutions(self, index: DefIndex) -> DocLinkResMap {
self.root
.tables
.doc_link_resolutions
.get(self, index)
.expect("no resolutions for a doc link")
.decode(self)
}
fn get_doc_link_traits_in_scope(self, index: DefIndex) -> impl Iterator<Item = DefId> {
self.root
.tables
.doc_link_traits_in_scope
.get(self, index)
.expect("no traits in scope for a doc link")
.decode(self)
}
}
impl CrateMetadata {
pub(crate) fn new(
sess: &Session,
cstore: &CStore,
blob: MetadataBlob,
root: CrateRoot,
raw_proc_macros: Option<&'static [ProcMacro]>,
cnum: CrateNum,
cnum_map: CrateNumMap,
dep_kind: CrateDepKind,
source: CrateSource,
private_dep: bool,
host_hash: Option<Svh>,
) -> CrateMetadata {
let trait_impls = root
.impls
.decode((&blob, sess))
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
.collect();
let alloc_decoding_state =
AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
2023-03-14 12:30:16 +00:00
let dependencies = cnum_map.iter().copied().collect();
// Pre-decode the DefPathHash->DefIndex table. This is a cheap operation
// that does not copy any data. It just does some data verification.
let def_path_hash_map = root.def_path_hash_map.decode(&blob);
let mut cdata = CrateMetadata {
blob,
root,
trait_impls,
incoherent_impls: Default::default(),
raw_proc_macros,
2022-08-06 23:27:45 +02:00
source_map_import_info: Lock::new(Vec::new()),
def_path_hash_map,
expn_hash_map: Default::default(),
alloc_decoding_state,
cnum,
cnum_map,
dependencies,
dep_kind,
source: Arc::new(source),
private_dep,
host_hash,
used: false,
extern_crate: None,
hygiene_context: Default::default(),
def_key_cache: Default::default(),
};
// Need `CrateMetadataRef` to decode `DefId`s in simplified types.
cdata.incoherent_impls = cdata
.root
.incoherent_impls
.decode(CrateMetadataRef { cdata: &cdata, cstore })
.map(|incoherent_impls| (incoherent_impls.self_ty, incoherent_impls.impls))
.collect();
cdata
}
pub(crate) fn dependencies(&self) -> impl Iterator<Item = CrateNum> {
self.dependencies.iter().copied()
}
pub(crate) fn add_dependency(&mut self, cnum: CrateNum) {
2023-03-14 12:30:16 +00:00
self.dependencies.push(cnum);
}
pub(crate) fn target_modifiers(&self) -> TargetModifiers {
self.root.decode_target_modifiers(&self.blob).collect()
}
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
let update =
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
if update {
self.extern_crate = Some(new_extern_crate);
}
update
}
pub(crate) fn source(&self) -> &CrateSource {
&*self.source
}
pub(crate) fn dep_kind(&self) -> CrateDepKind {
self.dep_kind
}
pub(crate) fn set_dep_kind(&mut self, dep_kind: CrateDepKind) {
self.dep_kind = dep_kind;
}
pub(crate) fn update_and_private_dep(&mut self, private_dep: bool) {
self.private_dep &= private_dep;
}
pub(crate) fn used(&self) -> bool {
self.used
}
pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> {
self.root.required_panic_strategy
}
pub(crate) fn needs_panic_runtime(&self) -> bool {
self.root.needs_panic_runtime
}
pub(crate) fn is_private_dep(&self) -> bool {
self.private_dep
}
pub(crate) fn is_panic_runtime(&self) -> bool {
self.root.panic_runtime
}
pub(crate) fn is_profiler_runtime(&self) -> bool {
self.root.profiler_runtime
}
pub(crate) fn is_compiler_builtins(&self) -> bool {
self.root.compiler_builtins
}
pub(crate) fn needs_allocator(&self) -> bool {
self.root.needs_allocator
}
pub(crate) fn has_global_allocator(&self) -> bool {
self.root.has_global_allocator
}
pub(crate) fn has_alloc_error_handler(&self) -> bool {
self.root.has_alloc_error_handler
}
pub(crate) fn has_default_lib_allocator(&self) -> bool {
self.root.has_default_lib_allocator
}
pub(crate) fn is_proc_macro_crate(&self) -> bool {
self.root.is_proc_macro_crate()
}
pub(crate) fn name(&self) -> Symbol {
self.root.header.name
}
pub(crate) fn hash(&self) -> Svh {
self.root.header.hash
}
fn num_def_ids(&self) -> usize {
self.root.tables.def_keys.size()
}
fn local_def_id(&self, index: DefIndex) -> DefId {
DefId { krate: self.cnum, index }
}
// Translate a DefId from the current compilation environment to a DefId
// for an external crate.
fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
for (local, &global) in self.cnum_map.iter_enumerated() {
if global == did.krate {
return Some(DefId { krate: local, index: did.index });
}
}
None
}
}