rust/src/librustc_metadata/rmeta/encoder.rs

1871 lines
74 KiB
Rust
Raw Normal View History

use crate::rmeta::table::FixedSizeEncoding;
2019-12-22 23:42:04 +01:00
use crate::rmeta::*;
use log::{debug, trace};
2020-01-07 17:25:33 +01:00
use rustc::hir::map::Map;
2019-12-22 23:42:04 +01:00
use rustc::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLibrary};
use rustc::middle::dependency_format::Linkage;
2019-12-22 23:42:04 +01:00
use rustc::middle::exported_symbols::{metadata_symbol_name, ExportedSymbol, SymbolExportLevel};
use rustc::middle::lang_items;
use rustc::mir::{self, interpret};
use rustc::traits::specialization_graph;
use rustc::ty::codec::{self as ty_codec, TyEncoder};
use rustc::ty::layout::VariantIdx;
2019-12-22 23:42:04 +01:00
use rustc::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_ast::ast;
use rustc_ast::attr;
2019-12-22 23:42:04 +01:00
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{join, Lrc};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefIdSet;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::DefPathTable;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
use rustc_hir::{AnonConst, GenericParamKind};
2019-12-22 23:42:04 +01:00
use rustc_index::vec::Idx;
use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder};
use rustc_session::config::{self, CrateType};
use rustc_span::source_map::Spanned;
2020-01-01 19:30:57 +01:00
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span};
use std::hash::Hash;
use std::num::NonZeroUsize;
use std::path::Path;
use std::u32;
struct EncodeContext<'tcx> {
opaque: opaque::Encoder,
tcx: TyCtxt<'tcx>,
per_def: PerDefTableBuilders<'tcx>,
lazy_state: LazyState,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
interpret_allocs: FxHashMap<interpret::AllocId, usize>,
interpret_allocs_inverse: Vec<interpret::AllocId>,
// This is used to speed up Span encoding.
2018-08-18 12:13:56 +02:00
source_file_cache: Lrc<SourceFile>,
}
macro_rules! encoder_methods {
($($name:ident($ty:ty);)*) => {
$(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
self.opaque.$name(value)
})*
}
}
impl<'tcx> Encoder for EncodeContext<'tcx> {
type Error = <opaque::Encoder as Encoder>::Error;
2018-09-11 16:32:41 +02:00
fn emit_unit(&mut self) -> Result<(), Self::Error> {
Ok(())
}
encoder_methods! {
emit_usize(usize);
emit_u128(u128);
emit_u64(u64);
emit_u32(u32);
emit_u16(u16);
emit_u8(u8);
emit_isize(isize);
emit_i128(i128);
emit_i64(i64);
emit_i32(i32);
emit_i16(i16);
emit_i8(i8);
emit_bool(bool);
emit_f64(f64);
emit_f32(f32);
emit_char(char);
emit_str(&str);
}
}
impl<'tcx, T> SpecializedEncoder<Lazy<T>> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
self.emit_lazy_distance(*lazy)
}
}
impl<'tcx, T> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, lazy: &Lazy<[T]>) -> Result<(), Self::Error> {
self.emit_usize(lazy.meta)?;
if lazy.meta == 0 {
return Ok(());
}
self.emit_lazy_distance(*lazy)
}
}
impl<'tcx, I: Idx, T> SpecializedEncoder<Lazy<Table<I, T>>> for EncodeContext<'tcx>
2019-12-22 23:42:04 +01:00
where
Option<T>: FixedSizeEncoding,
{
fn specialized_encode(&mut self, lazy: &Lazy<Table<I, T>>) -> Result<(), Self::Error> {
self.emit_usize(lazy.meta)?;
self.emit_lazy_distance(*lazy)
}
}
impl<'tcx> SpecializedEncoder<CrateNum> for EncodeContext<'tcx> {
#[inline]
fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
self.emit_u32(cnum.as_u32())
}
}
impl<'tcx> SpecializedEncoder<DefId> for EncodeContext<'tcx> {
#[inline]
fn specialized_encode(&mut self, def_id: &DefId) -> Result<(), Self::Error> {
2019-12-22 23:42:04 +01:00
let DefId { krate, index } = *def_id;
krate.encode(self)?;
index.encode(self)
}
}
impl<'tcx> SpecializedEncoder<DefIndex> for EncodeContext<'tcx> {
#[inline]
fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> {
self.emit_u32(def_index.as_u32())
}
}
impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
2018-06-25 00:00:21 +02:00
if span.is_dummy() {
2019-12-22 23:42:04 +01:00
return TAG_INVALID_SPAN.encode(self);
}
let span = span.data();
// The Span infrastructure should make sure that this invariant holds:
debug_assert!(span.lo <= span.hi);
2018-08-18 12:13:56 +02:00
if !self.source_file_cache.contains(span.lo) {
2018-08-18 12:14:14 +02:00
let source_map = self.tcx.sess.source_map();
let source_file_index = source_map.lookup_source_file_idx(span.lo);
self.source_file_cache = source_map.files()[source_file_index].clone();
}
2018-08-18 12:13:56 +02:00
if !self.source_file_cache.contains(span.hi) {
// Unfortunately, macro expansion still sometimes generates Spans
// that malformed in this way.
2019-12-22 23:42:04 +01:00
return TAG_INVALID_SPAN.encode(self);
}
// 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
// deserialized, the deserializer will need to know which crate it originally came
// from. We use `TAG_VALID_SPAN_FOREIGN` to indicate that a `CrateNum` should
// be deserialized after the rest of the span data, which tells the deserializer
// which crate contains the source map information.
// 2. This span comes from our own crate. No special hamdling is needed - we just
// write `TAG_VALID_SPAN_LOCAL` to let the deserializer know that it should use
// our own source map information.
let (tag, lo, hi) = if self.source_file_cache.is_imported() {
// 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
// we write into the metadata. This allows `imported_source_files` to binary
// search through the 'foreign' crate's source map information, using the
// deserialized 'lo' and 'hi' values directly.
//
// 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 = {
// Introduce a new scope so that we drop the 'lock()' temporary
match &*self.source_file_cache.external_src.lock() {
ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos,
src => panic!("Unexpected external source {:?}", src),
}
};
let lo = (span.lo - self.source_file_cache.start_pos) + external_start_pos;
let hi = (span.hi - self.source_file_cache.start_pos) + external_start_pos;
(TAG_VALID_SPAN_FOREIGN, lo, hi)
} else {
(TAG_VALID_SPAN_LOCAL, span.lo, span.hi)
};
tag.encode(self)?;
lo.encode(self)?;
// 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;
len.encode(self)?;
if tag == TAG_VALID_SPAN_FOREIGN {
// This needs to be two lines to avoid holding the `self.source_file_cache`
// while calling `cnum.encode(self)`
let cnum = self.source_file_cache.cnum;
cnum.encode(self)?;
}
Ok(())
// Don't encode the expansion context.
}
}
impl SpecializedEncoder<Ident> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, ident: &Ident) -> Result<(), Self::Error> {
// FIXME(jseyfried): intercrate hygiene
ident.name.encode(self)
}
}
impl<'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'tcx> {
#[inline]
fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> {
self.specialized_encode(&def_id.to_def_id())
}
}
impl<'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands)
}
}
impl<'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
2018-04-13 18:48:41 +02:00
use std::collections::hash_map::Entry;
let index = match self.interpret_allocs.entry(*alloc_id) {
Entry::Occupied(e) => *e.get(),
Entry::Vacant(e) => {
let idx = self.interpret_allocs_inverse.len();
self.interpret_allocs_inverse.push(*alloc_id);
e.insert(idx);
idx
2019-12-22 23:42:04 +01:00
}
};
index.encode(self)
}
}
impl<'tcx> SpecializedEncoder<&'tcx [(ty::Predicate<'tcx>, Span)]> for EncodeContext<'tcx> {
2019-12-22 23:42:04 +01:00
fn specialized_encode(
&mut self,
predicates: &&'tcx [(ty::Predicate<'tcx>, Span)],
) -> Result<(), Self::Error> {
ty_codec::encode_spanned_predicates(self, predicates, |ecx| &mut ecx.predicate_shorthands)
}
}
impl<'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
f.encode_opaque(&mut self.opaque)
}
}
impl<'tcx, T: Encodable> SpecializedEncoder<mir::ClearCrossCrate<T>> for EncodeContext<'tcx> {
2019-12-22 23:42:04 +01:00
fn specialized_encode(&mut self, _: &mir::ClearCrossCrate<T>) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'tcx> TyEncoder for EncodeContext<'tcx> {
fn position(&self) -> usize {
self.opaque.position()
}
}
/// Helper trait to allow overloading `EncodeContext::lazy` for iterators.
trait EncodeContentsForLazy<T: ?Sized + LazyMeta> {
fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) -> T::Meta;
}
impl<T: Encodable> EncodeContentsForLazy<T> for &T {
fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) {
self.encode(ecx).unwrap()
}
}
impl<T: Encodable> EncodeContentsForLazy<T> for T {
fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) {
self.encode(ecx).unwrap()
}
}
impl<I, T: Encodable> EncodeContentsForLazy<[T]> for I
2019-12-22 23:42:04 +01:00
where
I: IntoIterator,
I::Item: EncodeContentsForLazy<T>,
{
fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) -> usize {
self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count()
}
}
// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy($value))`, which would
// normally need extra variables to avoid errors about multiple mutable borrows.
macro_rules! record {
($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
{
let value = $value;
let lazy = $self.lazy(value);
$self.$tables.$table.set($def_id.index, lazy);
}
2019-12-22 23:42:04 +01:00
}};
}
impl<'tcx> EncodeContext<'tcx> {
fn emit_lazy_distance<T: ?Sized + LazyMeta>(
&mut self,
lazy: Lazy<T>,
) -> Result<(), <Self as Encoder>::Error> {
let min_end = lazy.position.get() + T::min_size(lazy.meta);
let distance = match self.lazy_state {
LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
LazyState::NodeStart(start) => {
let start = start.get();
assert!(min_end <= start);
start - min_end
}
LazyState::Previous(last_min_end) => {
2018-04-11 10:47:52 +02:00
assert!(
last_min_end <= lazy.position,
2018-04-11 10:47:52 +02:00
"make sure that the calls to `lazy*` \
2020-01-26 02:09:23 +01:00
are in the same order as the metadata fields",
2018-04-11 10:47:52 +02:00
);
lazy.position.get() - last_min_end.get()
}
};
self.lazy_state = LazyState::Previous(NonZeroUsize::new(min_end).unwrap());
self.emit_usize(distance)
}
2019-12-22 23:42:04 +01:00
fn lazy<T: ?Sized + LazyMeta>(&mut self, value: impl EncodeContentsForLazy<T>) -> Lazy<T> {
let pos = NonZeroUsize::new(self.position()).unwrap();
assert_eq!(self.lazy_state, LazyState::NoNode);
self.lazy_state = LazyState::NodeStart(pos);
let meta = value.encode_contents_for_lazy(self);
self.lazy_state = LazyState::NoNode;
assert!(pos.get() + <T>::min_size(meta) <= self.position());
Lazy::from_position_and_meta(pos, meta)
}
fn encode_info_for_items(&mut self) {
let krate = self.tcx.hir().krate();
let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public };
2020-02-07 16:43:36 +01:00
self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs, &vis);
krate.visit_all_item_likes(&mut self.as_deep_visitor());
2019-11-28 11:49:29 +01:00
for macro_def in krate.exported_macros {
self.visit_macro_def(macro_def);
}
}
fn encode_def_path_table(&mut self) -> Lazy<DefPathTable> {
let definitions = self.tcx.hir().definitions();
self.lazy(definitions.def_path_table())
}
fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
2018-08-18 12:14:14 +02:00
let source_map = self.tcx.sess.source_map();
let all_source_files = source_map.files();
let (working_dir, _cwd_remapped) = self.tcx.sess.working_dir.clone();
2019-12-22 23:42:04 +01:00
let adapted = all_source_files
.iter()
2018-08-18 12:13:56 +02:00
.filter(|source_file| {
// No need to re-export imported source_files, as any downstream
// crate will import them from their original source.
// FIXME(eddyb) the `Span` encoding should take that into account.
2018-08-18 12:13:56 +02:00
!source_file.is_imported()
})
2018-08-18 12:13:56 +02:00
.map(|source_file| {
match source_file.name {
// This path of this SourceFile has been modified by
// path-remapping, so we use it verbatim (and avoid
// cloning the whole map in the process).
2019-12-22 23:42:04 +01:00
_ if source_file.name_was_remapped => source_file.clone(),
// Otherwise expand all paths to absolute paths because
// any relative paths are potentially relative to a
// wrong directory.
FileName::Real(ref name) => {
let mut adapted = (**source_file).clone();
adapted.name = Path::new(&working_dir).join(name).into();
adapted.name_hash = {
let mut hasher: StableHasher = StableHasher::new();
adapted.name.hash(&mut hasher);
hasher.finish::<u128>()
};
Lrc::new(adapted)
2019-12-22 23:42:04 +01:00
}
// expanded code, not from a file
2018-08-18 12:13:56 +02:00
_ => source_file.clone(),
}
})
.collect::<Vec<_>>();
self.lazy(adapted.iter().map(|rc| &**rc))
}
fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
let mut i = self.position();
let crate_deps = self.encode_crate_deps();
let dylib_dependency_formats = self.encode_dylib_dependency_formats();
let dep_bytes = self.position() - i;
// Encode the lib features.
i = self.position();
let lib_features = self.encode_lib_features();
let lib_feature_bytes = self.position() - i;
// Encode the language items.
i = self.position();
let lang_items = self.encode_lang_items();
let lang_items_missing = self.encode_lang_items_missing();
let lang_item_bytes = self.position() - i;
// Encode the diagnostic items.
i = self.position();
let diagnostic_items = self.encode_diagnostic_items();
let diagnostic_item_bytes = self.position() - i;
// Encode the native libraries used
i = self.position();
let native_libraries = self.encode_native_libraries();
let native_lib_bytes = self.position() - i;
let foreign_modules = self.encode_foreign_modules();
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 23:28:17 +01:00
2018-08-18 12:14:14 +02:00
// Encode source_map
i = self.position();
2018-08-18 12:14:14 +02:00
let source_map = self.encode_source_map();
let source_map_bytes = self.position() - i;
// Encode DefPathTable
i = self.position();
let def_path_table = self.encode_def_path_table();
let def_path_table_bytes = self.position() - i;
// Encode the def IDs of impls, for coherence checking.
i = self.position();
let impls = self.encode_impls();
let impl_bytes = self.position() - i;
let tcx = self.tcx;
// Encode the items.
i = self.position();
self.encode_info_for_items();
let item_bytes = self.position() - i;
// Encode the allocation index
let interpret_alloc_index = {
let mut interpret_alloc_index = Vec::new();
let mut n = 0;
trace!("beginning to encode alloc ids");
loop {
2018-04-13 18:48:41 +02:00
let new_n = self.interpret_allocs_inverse.len();
// if we have found new ids, serialize those, too
if n == new_n {
// otherwise, abort
break;
}
trace!("encoding {} further alloc ids", new_n - n);
for idx in n..new_n {
let id = self.interpret_allocs_inverse[idx];
let pos = self.position() as u32;
interpret_alloc_index.push(pos);
2019-12-22 23:42:04 +01:00
interpret::specialized_encode_alloc_id(self, tcx, id).unwrap();
}
n = new_n;
}
self.lazy(interpret_alloc_index)
};
2018-04-11 10:47:52 +02:00
i = self.position();
let per_def = self.per_def.encode(&mut self.opaque);
let per_def_bytes = self.position() - i;
2018-04-11 10:47:52 +02:00
// Encode the proc macro data
i = self.position();
let proc_macro_data = self.encode_proc_macros();
let proc_macro_data_bytes = self.position() - i;
2020-03-14 13:39:33 +01:00
// Encode exported symbols info. This is prefetched in `encode_metadata` so we encode
// this last to give the prefetching as much time as possible to complete.
2020-01-11 03:42:40 +01:00
i = self.position();
let exported_symbols = self.tcx.exported_symbols(LOCAL_CRATE);
let exported_symbols = self.encode_exported_symbols(&exported_symbols);
let exported_symbols_bytes = self.position() - i;
let attrs = tcx.hir().krate_attrs();
let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
2018-04-11 10:47:52 +02:00
let root = self.lazy(CrateRoot {
name: tcx.crate_name(LOCAL_CRATE),
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
triple: tcx.sess.opts.target_triple.clone(),
2018-08-18 12:08:06 +02:00
hash: tcx.crate_hash(LOCAL_CRATE),
disambiguator: tcx.sess.local_crate_disambiguator(),
panic_strategy: tcx.sess.panic_strategy(),
edition: tcx.sess.edition(),
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
2019-10-28 22:07:15 +01:00
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
has_default_lib_allocator,
2019-01-13 01:06:50 +01:00
plugin_registrar_fn: tcx.plugin_registrar_fn(LOCAL_CRATE).map(|id| id.index),
proc_macro_decls_static: if is_proc_macro {
2019-01-12 21:49:18 +01:00
let id = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap();
Some(id.index)
} else {
None
},
proc_macro_data,
2019-01-28 23:40:14 +01:00
proc_macro_stability: if is_proc_macro {
tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied()
2019-01-28 23:40:14 +01:00
} else {
None
},
compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
no_builtins: attr::contains_name(&attrs, sym::no_builtins),
panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version,
crate_deps,
dylib_dependency_formats,
lib_features,
lang_items,
diagnostic_items,
lang_items_missing,
native_libraries,
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 23:28:17 +01:00
foreign_modules,
2018-08-18 12:14:14 +02:00
source_map,
def_path_table,
impls,
exported_symbols,
interpret_alloc_index,
per_def,
});
let total_bytes = self.position();
if self.tcx.sess.meta_stats() {
let mut zero_bytes = 0;
for e in self.opaque.data.iter() {
if *e == 0 {
zero_bytes += 1;
}
}
println!("metadata stats:");
println!(" dep bytes: {}", dep_bytes);
println!(" lib feature bytes: {}", lib_feature_bytes);
println!(" lang item bytes: {}", lang_item_bytes);
println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
println!(" native bytes: {}", native_lib_bytes);
2018-08-18 12:14:14 +02:00
println!(" source_map bytes: {}", source_map_bytes);
println!(" impl bytes: {}", impl_bytes);
println!(" exp. symbols bytes: {}", exported_symbols_bytes);
println!(" def-path table bytes: {}", def_path_table_bytes);
println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
println!(" item bytes: {}", item_bytes);
println!(" per-def table bytes: {}", per_def_bytes);
println!(" zero bytes: {}", zero_bytes);
println!(" total bytes: {}", total_bytes);
}
root
}
}
impl EncodeContext<'tcx> {
fn encode_variances_of(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_variances_of({:?})", def_id);
record!(self.per_def.variances[def_id] <- &self.tcx.variances_of(def_id)[..]);
}
fn encode_item_type(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_item_type({:?})", def_id);
record!(self.per_def.ty[def_id] <- self.tcx.type_of(def_id));
}
2019-12-22 23:42:04 +01:00
fn encode_enum_variant_info(&mut self, enum_did: DefId, index: VariantIdx) {
let tcx = self.tcx;
let def = tcx.adt_def(enum_did);
let variant = &def.variants[index];
2019-03-24 10:09:44 +01:00
let def_id = variant.def_id;
debug!("EncodeContext::encode_enum_variant_info({:?})", def_id);
let data = VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
2019-03-24 10:09:44 +01:00
ctor: variant.ctor_def_id.map(|did| did.index),
};
2019-02-27 17:35:24 +01:00
let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
let enum_vis = &tcx.hir().expect_item(enum_id).vis;
record!(self.per_def.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
record!(self.per_def.visibility[def_id] <-
ty::Visibility::from_hir(enum_vis, enum_id, self.tcx));
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
record!(self.per_def.children[def_id] <- variant.fields.iter().map(|f| {
assert!(f.did.is_local());
f.did.index
}));
self.encode_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
// FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
if let Some(ctor_def_id) = variant.ctor_def_id {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id));
}
// FIXME(eddyb) is this ever used?
self.encode_variances_of(def_id);
}
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
2019-12-22 23:42:04 +01:00
fn encode_enum_variant_ctor(&mut self, enum_did: DefId, index: VariantIdx) {
let tcx = self.tcx;
let def = tcx.adt_def(enum_did);
let variant = &def.variants[index];
2019-03-24 10:09:44 +01:00
let def_id = variant.ctor_def_id.unwrap();
debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id);
// FIXME(eddyb) encode only the `CtorKind` for constructors.
let data = VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
ctor: Some(def_id.index),
};
// Variant constructors have the same visibility as the parent enums, unless marked as
// non-exhaustive, in which case they are lowered to `pub(crate)`.
let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
let enum_vis = &tcx.hir().expect_item(enum_id).vis;
let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx);
if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public {
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
}
record!(self.per_def.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
record!(self.per_def.visibility[def_id] <- ctor_vis);
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
self.encode_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
self.encode_variances_of(def_id);
}
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
fn encode_info_for_mod(
&mut self,
id: hir::HirId,
2019-11-29 10:24:47 +01:00
md: &hir::Mod<'_>,
attrs: &[ast::Attribute],
2019-12-01 16:08:58 +01:00
vis: &hir::Visibility<'_>,
) {
let tcx = self.tcx;
let def_id = tcx.hir().local_def_id(id);
debug!("EncodeContext::encode_info_for_mod({:?})", def_id);
let data = ModData {
reexports: match tcx.module_exports(def_id) {
Some(exports) => self.lazy(exports),
_ => Lazy::empty(),
},
};
record!(self.per_def.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
record!(self.per_def.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx));
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
record!(self.per_def.attributes[def_id] <- attrs);
record!(self.per_def.children[def_id] <- md.item_ids.iter().map(|item_id| {
tcx.hir().local_def_id(item_id.id).index
}));
self.encode_stability(def_id);
self.encode_deprecation(def_id);
}
2016-08-12 22:18:22 +02:00
2019-12-22 23:42:04 +01:00
fn encode_field(&mut self, adt_def_id: DefId, variant_index: VariantIdx, field_index: usize) {
let tcx = self.tcx;
let variant = &tcx.adt_def(adt_def_id).variants[variant_index];
2016-08-12 22:18:22 +02:00
let field = &variant.fields[field_index];
let def_id = field.did;
debug!("EncodeContext::encode_field({:?})", def_id);
2019-03-24 10:09:44 +01:00
let variant_id = tcx.hir().as_local_hir_id(variant.def_id).unwrap();
let variant_data = tcx.hir().expect_variant_data(variant_id);
record!(self.per_def.kind[def_id] <- EntryKind::Field);
record!(self.per_def.visibility[def_id] <- field.vis);
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
2019-11-29 09:40:33 +01:00
record!(self.per_def.attributes[def_id] <- variant_data.fields()[field_index].attrs);
self.encode_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
}
fn encode_struct_ctor(&mut self, adt_def_id: DefId, def_id: DefId) {
debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
let tcx = self.tcx;
let adt_def = tcx.adt_def(adt_def_id);
let variant = adt_def.non_enum_variant();
let data = VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
ctor: Some(def_id.index),
};
2019-02-27 17:35:24 +01:00
let struct_id = tcx.hir().as_local_hir_id(adt_def_id).unwrap();
let struct_vis = &tcx.hir().expect_item(struct_id).vis;
let mut ctor_vis = ty::Visibility::from_hir(struct_vis, struct_id, tcx);
for field in &variant.fields {
if ctor_vis.is_at_least(field.vis, tcx) {
ctor_vis = field.vis;
}
}
// If the structure is marked as non_exhaustive then lower the visibility
// to within the crate.
2019-12-22 23:42:04 +01:00
if adt_def.non_enum_variant().is_field_list_non_exhaustive()
&& ctor_vis == ty::Visibility::Public
{
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
}
record!(self.per_def.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
record!(self.per_def.visibility[def_id] <- ctor_vis);
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
self.encode_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
self.encode_variances_of(def_id);
}
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
fn encode_generics(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_generics({:?})", def_id);
record!(self.per_def.generics[def_id] <- self.tcx.generics_of(def_id));
}
fn encode_explicit_predicates(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_explicit_predicates({:?})", def_id);
record!(self.per_def.explicit_predicates[def_id] <-
self.tcx.explicit_predicates_of(def_id));
}
fn encode_inferred_outlives(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_inferred_outlives({:?})", def_id);
let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
if !inferred_outlives.is_empty() {
record!(self.per_def.inferred_outlives[def_id] <- inferred_outlives);
}
}
fn encode_super_predicates(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_super_predicates({:?})", def_id);
record!(self.per_def.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id));
}
fn encode_info_for_trait_item(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx;
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let ast_item = tcx.hir().expect_trait_item(hir_id);
let trait_item = tcx.associated_item(def_id);
let container = match trait_item.defaultness {
2019-12-22 23:42:04 +01:00
hir::Defaultness::Default { has_value: true } => AssocContainer::TraitWithDefault,
hir::Defaultness::Default { has_value: false } => AssocContainer::TraitRequired,
hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"),
};
record!(self.per_def.kind[def_id] <- match trait_item.kind {
ty::AssocKind::Const => {
let rendered = rustc_hir_pretty::to_string(
&(&self.tcx.hir() as &dyn intravisit::Map<'_>),
|s| s.print_trait_item(ast_item)
);
let rendered_const = self.lazy(RenderedConst(rendered));
2018-04-16 01:41:33 +02:00
EntryKind::AssocConst(
container,
Default::default(),
rendered_const,
)
}
ty::AssocKind::Method => {
2020-03-03 19:46:22 +01:00
let fn_data = if let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind {
let param_names = match *m {
2020-03-05 16:57:34 +01:00
hir::TraitFn::Required(ref names) => {
self.encode_fn_param_names(names)
}
2020-03-05 16:57:34 +01:00
hir::TraitFn::Provided(body) => {
self.encode_fn_param_names_for_body(body)
}
};
FnData {
asyncness: m_sig.header.asyncness,
constness: hir::Constness::NotConst,
param_names,
}
} else {
bug!()
};
2020-03-15 17:19:17 +01:00
EntryKind::AssocFn(self.lazy(AssocFnData {
fn_data,
container,
has_self: trait_item.method_has_self_argument,
}))
}
ty::AssocKind::Type => EntryKind::AssocType(container),
2019-08-01 01:41:54 +02:00
ty::AssocKind::OpaqueTy => span_bug!(ast_item.span, "opaque type in trait"),
});
record!(self.per_def.visibility[def_id] <- trait_item.vis);
record!(self.per_def.span[def_id] <- ast_item.span);
2019-11-28 21:47:10 +01:00
record!(self.per_def.attributes[def_id] <- ast_item.attrs);
self.encode_stability(def_id);
self.encode_const_stability(def_id);
self.encode_deprecation(def_id);
match trait_item.kind {
2019-12-22 23:42:04 +01:00
ty::AssocKind::Const | ty::AssocKind::Method => {
self.encode_item_type(def_id);
}
ty::AssocKind::Type => {
if trait_item.defaultness.has_value() {
self.encode_item_type(def_id);
}
}
ty::AssocKind::OpaqueTy => unreachable!(),
}
if trait_item.kind == ty::AssocKind::Method {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
self.encode_variances_of(def_id);
}
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
2020-03-14 13:39:33 +01:00
// This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
2018-03-27 23:53:30 +02:00
fn metadata_output_only(&self) -> bool {
// MIR optimisation can be skipped when we're just interested in the metadata.
2018-05-08 15:10:16 +02:00
!self.tcx.sess.opts.output_types.should_codegen()
2018-03-27 23:53:30 +02:00
}
fn encode_info_for_impl_item(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
let tcx = self.tcx;
let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap();
let ast_item = self.tcx.hir().expect_impl_item(hir_id);
let impl_item = self.tcx.associated_item(def_id);
let container = match impl_item.defaultness {
hir::Defaultness::Default { has_value: true } => AssocContainer::ImplDefault,
hir::Defaultness::Final => AssocContainer::ImplFinal,
2019-12-22 23:42:04 +01:00
hir::Defaultness::Default { has_value: false } => {
span_bug!(ast_item.span, "impl items always have values (currently)")
}
};
record!(self.per_def.kind[def_id] <- match impl_item.kind {
ty::AssocKind::Const => {
if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
2018-04-16 01:41:33 +02:00
EntryKind::AssocConst(
container,
qualifs,
2018-04-16 01:41:33 +02:00
self.encode_rendered_const_for_body(body_id))
} else {
bug!()
}
}
ty::AssocKind::Method => {
2020-03-05 16:57:34 +01:00
let fn_data = if let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind {
FnData {
2019-09-19 05:02:08 +02:00
asyncness: sig.header.asyncness,
constness: sig.header.constness,
param_names: self.encode_fn_param_names_for_body(body),
}
} else {
bug!()
};
2020-03-15 17:19:17 +01:00
EntryKind::AssocFn(self.lazy(AssocFnData {
fn_data,
container,
has_self: impl_item.method_has_self_argument,
}))
}
2019-08-01 01:41:54 +02:00
ty::AssocKind::OpaqueTy => EntryKind::AssocOpaqueTy(container),
ty::AssocKind::Type => EntryKind::AssocType(container)
});
record!(self.per_def.visibility[def_id] <- impl_item.vis);
record!(self.per_def.span[def_id] <- ast_item.span);
2019-11-28 22:16:44 +01:00
record!(self.per_def.attributes[def_id] <- ast_item.attrs);
self.encode_stability(def_id);
self.encode_const_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if impl_item.kind == ty::AssocKind::Method {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
self.encode_variances_of(def_id);
}
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
2020-03-14 13:39:33 +01:00
// The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
let mir = match ast_item.kind {
hir::ImplItemKind::Const(..) => true,
2020-03-05 16:57:34 +01:00
hir::ImplItemKind::Fn(ref sig, _) => {
let generics = self.tcx.generics_of(def_id);
2019-12-22 23:42:04 +01:00
let needs_inline = (generics.requires_monomorphization(self.tcx)
|| tcx.codegen_fn_attrs(def_id).requests_inline())
&& !self.metadata_output_only();
let is_const_fn = sig.header.constness == hir::Constness::Const;
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
needs_inline || is_const_fn || always_encode_mir
2019-12-22 23:42:04 +01:00
}
hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => false,
};
if mir {
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
}
2019-12-22 23:42:04 +01:00
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[ast::Name]> {
self.tcx.dep_graph.with_ignore(|| {
let body = self.tcx.hir().body(body_id);
2019-12-22 23:42:04 +01:00
self.lazy(body.params.iter().map(|arg| match arg.pat.kind {
hir::PatKind::Binding(_, _, ident, _) => ident.name,
2019-12-22 23:42:04 +01:00
_ => kw::Invalid,
}))
})
}
fn encode_fn_param_names(&mut self, param_names: &[ast::Ident]) -> Lazy<[ast::Name]> {
self.lazy(param_names.iter().map(|ident| ident.name))
}
fn encode_optimized_mir(&mut self, def_id: DefId) {
debug!("EntryBuilder::encode_mir({:?})", def_id);
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
record!(self.per_def.mir[def_id] <- self.tcx.optimized_mir(def_id));
}
}
fn encode_promoted_mir(&mut self, def_id: DefId) {
2019-08-04 22:20:21 +02:00
debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
record!(self.per_def.promoted_mir[def_id] <- self.tcx.promoted_mir(def_id));
2019-08-04 22:20:21 +02:00
}
}
// Encodes the inherent implementations of a structure, enumeration, or trait.
fn encode_inherent_implementations(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_inherent_implementations({:?})", def_id);
let implementations = self.tcx.inherent_impls(def_id);
if !implementations.is_empty() {
record!(self.per_def.inherent_impls[def_id] <- implementations.iter().map(|&def_id| {
assert!(def_id.is_local());
def_id.index
}));
}
}
fn encode_stability(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_stability({:?})", def_id);
if let Some(stab) = self.tcx.lookup_stability(def_id) {
record!(self.per_def.stability[def_id] <- stab)
}
}
fn encode_const_stability(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_const_stability({:?})", def_id);
if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
record!(self.per_def.const_stability[def_id] <- stab)
}
}
fn encode_deprecation(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_deprecation({:?})", def_id);
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
record!(self.per_def.deprecation[def_id] <- depr);
}
}
2018-04-16 01:41:33 +02:00
fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy<RenderedConst> {
let hir = self.tcx.hir();
let body = hir.body(body_id);
let rendered = rustc_hir_pretty::to_string(&(&hir as &dyn intravisit::Map<'_>), |s| {
s.print_expr(&body.value)
});
2018-04-16 01:41:33 +02:00
let rendered_const = &RenderedConst(rendered);
self.lazy(rendered_const)
}
2019-11-28 19:28:50 +01:00
fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
let tcx = self.tcx;
debug!("EncodeContext::encode_info_for_item({:?})", def_id);
record!(self.per_def.kind[def_id] <- match item.kind {
hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic,
hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic,
2018-07-11 17:36:06 +02:00
hir::ItemKind::Const(_, body_id) => {
let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
2018-04-16 01:41:33 +02:00
EntryKind::Const(
qualifs,
2018-04-16 01:41:33 +02:00
self.encode_rendered_const_for_body(body_id)
)
}
2019-11-07 12:57:52 +01:00
hir::ItemKind::Fn(ref sig, .., body) => {
let data = FnData {
2019-11-07 12:57:52 +01:00
asyncness: sig.header.asyncness,
constness: sig.header.constness,
param_names: self.encode_fn_param_names_for_body(body),
};
EntryKind::Fn(self.lazy(data))
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::Mod(ref m) => {
return self.encode_info_for_mod(item.hir_id, m, &item.attrs, &item.vis);
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod,
hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
hir::ItemKind::TyAlias(..) => EntryKind::Type,
2019-08-01 01:41:54 +02:00
hir::ItemKind::OpaqueTy(..) => EntryKind::OpaqueTy,
hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr),
2018-07-11 17:36:06 +02:00
hir::ItemKind::Struct(ref struct_def, _) => {
let adt_def = self.tcx.adt_def(def_id);
let variant = adt_def.non_enum_variant();
// Encode def_ids for each field and method
// for methods, write all the stuff get_trait_method
// needs to know
let ctor = struct_def.ctor_hir_id().map(|ctor_hir_id| {
self.tcx.hir().local_def_id(ctor_hir_id).index
});
EntryKind::Struct(self.lazy(VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
ctor,
}), adt_def.repr)
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::Union(..) => {
let adt_def = self.tcx.adt_def(def_id);
let variant = adt_def.non_enum_variant();
2016-08-22 14:17:05 +02:00
EntryKind::Union(self.lazy(VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
ctor: None,
}), adt_def.repr)
2016-08-22 14:17:05 +02:00
}
hir::ItemKind::Impl { defaultness, .. } => {
let trait_ref = self.tcx.impl_trait_ref(def_id);
let polarity = self.tcx.impl_polarity(def_id);
let parent = if let Some(trait_ref) = trait_ref {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
trait_def.ancestors(self.tcx, def_id).ok()
.and_then(|mut an| an.nth(1).and_then(|node| {
match node {
specialization_graph::Node::Impl(parent) => Some(parent),
_ => None,
}
}))
} else {
None
};
// if this is an impl of `CoerceUnsized`, create its
// "unsized info", else just store None
let coerce_unsized_info =
trait_ref.and_then(|t| {
if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
Some(self.tcx.at(item.span).coerce_unsized_info(def_id))
} else {
None
}
});
let data = ImplData {
polarity,
defaultness,
parent_impl: parent,
coerce_unsized_info,
};
EntryKind::Impl(self.lazy(data))
}
hir::ItemKind::Trait(..) => {
let trait_def = self.tcx.trait_def(def_id);
let data = TraitData {
unsafety: trait_def.unsafety,
paren_sugar: trait_def.paren_sugar,
has_auto_impl: self.tcx.trait_is_auto(def_id),
2018-08-25 08:13:31 +02:00
is_marker: trait_def.is_marker,
specialization_kind: trait_def.specialization_kind,
};
EntryKind::Trait(self.lazy(data))
}
hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias,
2018-07-11 17:36:06 +02:00
hir::ItemKind::ExternCrate(_) |
hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
});
record!(self.per_def.visibility[def_id] <-
ty::Visibility::from_hir(&item.vis, item.hir_id, tcx));
record!(self.per_def.span[def_id] <- item.span);
2019-11-28 23:50:47 +01:00
record!(self.per_def.attributes[def_id] <- item.attrs);
// FIXME(eddyb) there should be a nicer way to do this.
match item.kind {
hir::ItemKind::ForeignMod(ref fm) => record!(self.per_def.children[def_id] <-
fm.items
.iter()
.map(|foreign_item| tcx.hir().local_def_id(
foreign_item.hir_id).index)
),
hir::ItemKind::Enum(..) => record!(self.per_def.children[def_id] <-
self.tcx.adt_def(def_id).variants.iter().map(|v| {
assert!(v.def_id.is_local());
v.def_id.index
})
),
2019-12-22 23:42:04 +01:00
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
record!(self.per_def.children[def_id] <-
self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
assert!(f.did.is_local());
f.did.index
})
)
}
hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => {
let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
record!(self.per_def.children[def_id] <-
associated_item_def_ids.iter().map(|&def_id| {
assert!(def_id.is_local());
def_id.index
})
);
}
_ => {}
}
self.encode_stability(def_id);
self.encode_const_stability(def_id);
self.encode_deprecation(def_id);
match item.kind {
2019-12-22 23:42:04 +01:00
hir::ItemKind::Static(..)
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..)
| hir::ItemKind::Impl { .. } => self.encode_item_type(def_id),
_ => {}
}
if let hir::ItemKind::Fn(..) = item.kind {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
}
if let hir::ItemKind::Impl { .. } = item.kind {
if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
record!(self.per_def.impl_trait_ref[def_id] <- trait_ref);
}
}
self.encode_inherent_implementations(def_id);
match item.kind {
2019-12-22 23:42:04 +01:00
hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..)
| hir::ItemKind::Fn(..) => self.encode_variances_of(def_id),
_ => {}
}
match item.kind {
2019-12-22 23:42:04 +01:00
hir::ItemKind::Static(..)
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..)
| hir::ItemKind::Impl { .. }
2019-12-22 23:42:04 +01:00
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::Trait(..)
| hir::ItemKind::TraitAlias(..) => {
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
}
_ => {}
}
match item.kind {
2019-12-22 23:42:04 +01:00
hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
self.encode_super_predicates(def_id);
}
_ => {}
}
2020-03-14 13:39:33 +01:00
// The following part should be kept in sync with `PrefetchVisitor.visit_item`.
2019-09-26 18:51:36 +02:00
let mir = match item.kind {
2019-08-04 22:20:21 +02:00
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
2019-11-07 12:57:52 +01:00
hir::ItemKind::Fn(ref sig, ..) => {
2019-08-04 22:20:21 +02:00
let generics = tcx.generics_of(def_id);
2019-12-22 23:42:04 +01:00
let needs_inline = (generics.requires_monomorphization(tcx)
|| tcx.codegen_fn_attrs(def_id).requests_inline())
&& !self.metadata_output_only();
2019-08-04 22:20:21 +02:00
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
2019-11-07 12:57:52 +01:00
needs_inline || sig.header.constness == hir::Constness::Const || always_encode_mir
2019-08-04 22:20:21 +02:00
}
_ => false,
};
if mir {
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
}
2016-10-28 08:52:45 +02:00
/// Serialize the text of exported macros
2019-11-28 23:50:47 +01:00
fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
let def_id = self.tcx.hir().local_def_id(macro_def.hir_id);
record!(self.per_def.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone())));
record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
record!(self.per_def.span[def_id] <- macro_def.span);
2019-11-28 23:50:47 +01:00
record!(self.per_def.attributes[def_id] <- macro_def.attrs);
self.encode_stability(def_id);
self.encode_deprecation(def_id);
2016-10-28 08:52:45 +02:00
}
2020-01-26 02:09:23 +01:00
fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
record!(self.per_def.kind[def_id] <- kind);
record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
if encode_type {
self.encode_item_type(def_id);
}
}
fn encode_info_for_closure(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
2016-08-15 00:50:53 +02:00
// NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
// including on the signature, which is inferred in `typeck_tables_of.
let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap();
let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id);
record!(self.per_def.kind[def_id] <- match ty.kind {
2020-01-26 02:09:23 +01:00
ty::Generator(..) => {
let data = self.tcx.generator_kind(def_id).unwrap();
2020-02-22 20:05:32 +01:00
EntryKind::Generator(data)
}
ty::Closure(..) => EntryKind::Closure,
_ => bug!("closure that is neither generator nor closure"),
});
record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
self.encode_item_type(def_id);
if let ty::Closure(def_id, substs) = ty.kind {
record!(self.per_def.fn_sig[def_id] <- substs.as_closure().sig());
}
self.encode_generics(def_id);
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
fn encode_info_for_anon_const(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id);
let id = self.tcx.hir().as_local_hir_id(def_id).unwrap();
let body_id = self.tcx.hir().body_owned_by(id);
2018-04-16 01:41:33 +02:00
let const_data = self.encode_rendered_const_for_body(body_id);
let qualifs = self.tcx.mir_const_qualif(def_id);
record!(self.per_def.kind[def_id] <- EntryKind::Const(qualifs, const_data));
record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
self.encode_item_type(def_id);
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
self.encode_optimized_mir(def_id);
self.encode_promoted_mir(def_id);
}
fn encode_native_libraries(&mut self) -> Lazy<[NativeLibrary]> {
let used_libraries = self.tcx.native_libraries(LOCAL_CRATE);
self.lazy(used_libraries.iter().cloned())
}
fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> {
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 23:28:17 +01:00
let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE);
self.lazy(foreign_modules.iter().cloned())
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 23:28:17 +01:00
}
fn encode_proc_macros(&mut self) -> Option<Lazy<[DefIndex]>> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
if is_proc_macro {
let tcx = self.tcx;
Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index)))
} else {
None
}
}
fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> {
let crates = self.tcx.crates();
let mut deps = crates
.iter()
.map(|&cnum| {
let dep = CrateDep {
name: self.tcx.original_crate_name(cnum),
2017-08-29 02:30:27 +02:00
hash: self.tcx.crate_hash(cnum),
host_hash: self.tcx.crate_host_hash(cnum),
kind: self.tcx.dep_kind(cnum),
extra_filename: self.tcx.extra_filename(cnum),
};
(cnum, dep)
})
.collect::<Vec<_>>();
deps.sort_by_key(|&(cnum, _)| cnum);
{
// Sanity-check the crate numbers
let mut expected_cnum = 1;
for &(n, _) in &deps {
assert_eq!(n, CrateNum::new(expected_cnum));
expected_cnum += 1;
}
}
// We're just going to write a list of crate 'name-hash-version's, with
// the assumption that they are numbered 1 to n.
// FIXME (#2166): This is not nearly enough to support correct versioning
// but is enough to get transitive crate dependencies working.
self.lazy(deps.iter().map(|&(_, ref dep)| dep))
}
fn encode_lib_features(&mut self) -> Lazy<[(ast::Name, Option<ast::Name>)]> {
let tcx = self.tcx;
let lib_features = tcx.lib_features();
self.lazy(lib_features.to_vec())
}
fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
let tcx = self.tcx;
let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE);
self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
}
fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> {
let tcx = self.tcx;
let lang_items = tcx.lang_items();
let lang_items = lang_items.items().iter();
self.lazy(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
if let Some(def_id) = opt_def_id {
if def_id.is_local() {
return Some((def_id.index, i));
}
}
None
}))
}
fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> {
let tcx = self.tcx;
self.lazy(&tcx.lang_items().missing)
}
/// Encodes an index, mapping each trait to its (local) implementations.
fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
debug!("EncodeContext::encode_impls()");
let tcx = self.tcx;
2019-12-22 23:42:04 +01:00
let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() };
tcx.hir().krate().visit_all_item_likes(&mut visitor);
let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
// Bring everything into deterministic order for hashing
2019-12-22 23:42:04 +01:00
all_impls.sort_by_cached_key(|&(trait_def_id, _)| tcx.def_path_hash(trait_def_id));
let all_impls: Vec<_> = all_impls
.into_iter()
.map(|(trait_def_id, mut impls)| {
// Bring everything into deterministic order for hashing
impls.sort_by_cached_key(|&index| {
tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index })
});
TraitImpls {
trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
impls: self.lazy(&impls),
}
})
.collect();
self.lazy(&all_impls)
}
// Encodes all symbols exported from this crate into the metadata.
//
// This pass is seeded off the reachability list calculated in the
// middle::reachable module but filters out items that either don't have a
// symbol associated with them (they weren't translated) or if they're an FFI
// definition (as that's not defined in this crate).
2019-12-22 23:42:04 +01:00
fn encode_exported_symbols(
&mut self,
exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)],
) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> {
// The metadata symbol name is special. It should not show up in
// downstream crates.
let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx));
2019-12-22 23:42:04 +01:00
self.lazy(
exported_symbols
.iter()
.filter(|&&(ref exported_symbol, _)| match *exported_symbol {
ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name,
_ => true,
2019-12-22 23:42:04 +01:00
})
.cloned(),
)
}
fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option<LinkagePreference>]> {
let formats = self.tcx.dependency_formats(LOCAL_CRATE);
for (ty, arr) in formats.iter() {
if *ty != config::CrateType::Dylib {
continue;
}
2019-12-22 23:42:04 +01:00
return self.lazy(arr.iter().map(|slot| match *slot {
Linkage::NotLinked | Linkage::IncludedFromDylib => None,
2019-12-22 23:42:04 +01:00
Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
Linkage::Static => Some(LinkagePreference::RequireStatic),
}));
}
Lazy::empty()
}
2019-12-22 23:42:04 +01:00
fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) {
let tcx = self.tcx;
debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id);
record!(self.per_def.kind[def_id] <- match nitem.kind {
2018-07-11 16:56:44 +02:00
hir::ForeignItemKind::Fn(_, ref names, _) => {
let data = FnData {
2019-09-19 05:02:08 +02:00
asyncness: hir::IsAsync::NotAsync,
constness: if self.tcx.is_const_fn_raw(def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
},
param_names: self.encode_fn_param_names(names),
};
EntryKind::ForeignFn(self.lazy(data))
}
hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => EntryKind::ForeignMutStatic,
hir::ForeignItemKind::Static(_, hir::Mutability::Not) => EntryKind::ForeignImmStatic,
2018-07-11 16:56:44 +02:00
hir::ForeignItemKind::Type => EntryKind::ForeignType,
});
record!(self.per_def.visibility[def_id] <-
ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, self.tcx));
record!(self.per_def.span[def_id] <- nitem.span);
2019-11-28 20:18:29 +01:00
record!(self.per_def.attributes[def_id] <- nitem.attrs);
self.encode_stability(def_id);
self.encode_const_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if let hir::ForeignItemKind::Fn(..) = nitem.kind {
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
self.encode_variances_of(def_id);
}
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
}
}
// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
impl Visitor<'tcx> for EncodeContext<'tcx> {
2020-01-07 17:25:33 +01:00
type Map = Map<'tcx>;
2020-02-09 15:32:00 +01:00
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::OnlyBodies(self.tcx.hir())
}
2019-11-30 15:08:22 +01:00
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
self.encode_info_for_expr(ex);
}
fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
intravisit::walk_anon_const(self, c);
let def_id = self.tcx.hir().local_def_id(c.hir_id);
self.encode_info_for_anon_const(def_id);
}
2019-11-28 19:28:50 +01:00
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
intravisit::walk_item(self, item);
let def_id = self.tcx.hir().local_def_id(item.hir_id);
2019-09-26 18:51:36 +02:00
match item.kind {
2019-12-22 23:42:04 +01:00
hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
_ => self.encode_info_for_item(def_id, item),
}
self.encode_addl_info_for_item(item);
}
2019-11-28 20:18:29 +01:00
fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
intravisit::walk_foreign_item(self, ni);
let def_id = self.tcx.hir().local_def_id(ni.hir_id);
self.encode_info_for_foreign_item(def_id, ni);
}
2019-12-01 16:08:58 +01:00
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
intravisit::walk_generics(self, generics);
self.encode_info_for_generics(generics);
}
2019-11-28 23:50:47 +01:00
fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
self.encode_info_for_macro_def(macro_def);
}
}
impl EncodeContext<'tcx> {
fn encode_fields(&mut self, adt_def_id: DefId) {
let def = self.tcx.adt_def(adt_def_id);
for (variant_index, variant) in def.variants.iter_enumerated() {
for (field_index, _field) in variant.fields.iter().enumerate() {
// FIXME(eddyb) `adt_def_id` is leftover from incremental isolation,
// pass `def`, `variant` or `field` instead.
self.encode_field(adt_def_id, variant_index, field_index);
}
}
}
2019-12-01 16:08:58 +01:00
fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) {
2019-12-01 17:10:12 +01:00
for param in generics.params {
let def_id = self.tcx.hir().local_def_id(param.hir_id);
2018-06-23 01:33:03 +02:00
match param.kind {
GenericParamKind::Lifetime { .. } => continue,
GenericParamKind::Type { ref default, .. } => {
self.encode_info_for_generic_param(
def_id,
EntryKind::TypeParam,
default.is_some(),
);
2018-06-23 01:33:03 +02:00
}
GenericParamKind::Const { .. } => {
self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true);
}
2018-05-26 01:27:54 +02:00
}
2018-06-23 01:33:03 +02:00
}
}
2019-11-30 15:08:22 +01:00
fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) {
match expr.kind {
2018-07-11 14:05:29 +02:00
hir::ExprKind::Closure(..) => {
let def_id = self.tcx.hir().local_def_id(expr.hir_id);
self.encode_info_for_closure(def_id);
}
_ => {}
}
}
/// In some cases, along with the item itself, we also
/// encode some sub-items. Usually we want some info from the item
/// so it's easier to do that here then to wait until we would encounter
/// normally in the visitor walk.
2019-11-28 19:28:50 +01:00
fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
let def_id = self.tcx.hir().local_def_id(item.hir_id);
2019-09-26 18:51:36 +02:00
match item.kind {
2019-12-22 23:42:04 +01:00
hir::ItemKind::Static(..)
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::ForeignMod(..)
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::TraitAlias(..) => {
// no sub-item recording needed in these cases
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::Enum(..) => {
self.encode_fields(def_id);
let def = self.tcx.adt_def(def_id);
for (i, variant) in def.variants.iter_enumerated() {
// FIXME(eddyb) `def_id` is leftover from incremental isolation,
// pass `def` or `variant` instead.
self.encode_enum_variant_info(def_id, i);
// FIXME(eddyb) `def_id` is leftover from incremental isolation,
// pass `def`, `variant` or `ctor_def_id` instead.
if let Some(_ctor_def_id) = variant.ctor_def_id {
self.encode_enum_variant_ctor(def_id, i);
}
}
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::Struct(ref struct_def, _) => {
self.encode_fields(def_id);
// If the struct has a constructor, encode it.
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
self.encode_struct_ctor(def_id, ctor_def_id);
}
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::Union(..) => {
self.encode_fields(def_id);
}
hir::ItemKind::Impl { .. } => {
for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() {
self.encode_info_for_impl_item(trait_item_def_id);
}
}
2018-07-11 17:36:06 +02:00
hir::ItemKind::Trait(..) => {
for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() {
self.encode_info_for_trait_item(item_def_id);
}
}
rustc: Implement custom panic runtimes This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
2016-04-09 01:18:40 +02:00
}
}
}
struct ImplVisitor<'tcx> {
2019-06-13 23:48:52 +02:00
tcx: TyCtxt<'tcx>,
impls: FxHashMap<DefId, Vec<DefIndex>>,
}
impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
2019-11-28 19:28:50 +01:00
fn visit_item(&mut self, item: &hir::Item<'_>) {
if let hir::ItemKind::Impl { .. } = item.kind {
let impl_id = self.tcx.hir().local_def_id(item.hir_id);
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) {
2019-12-22 23:42:04 +01:00
self.impls.entry(trait_ref.def_id).or_default().push(impl_id.index);
}
}
}
2019-11-28 21:47:10 +01:00
fn visit_trait_item(&mut self, _trait_item: &'v hir::TraitItem<'v>) {}
2019-11-28 22:16:44 +01:00
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem<'v>) {
// handled in `visit_item` above
rustc: Implement custom panic runtimes This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
2016-04-09 01:18:40 +02:00
}
}
/// Used to prefetch queries which will be needed later by metadata encoding.
2020-03-14 13:39:33 +01:00
/// Only a subset of the queries are actually prefetched to keep this code smaller.
struct PrefetchVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
mir_keys: &'tcx DefIdSet,
}
impl<'tcx> PrefetchVisitor<'tcx> {
fn prefetch_mir(&self, def_id: DefId) {
if self.mir_keys.contains(&def_id) {
self.tcx.optimized_mir(def_id);
self.tcx.promoted_mir(def_id);
}
}
}
impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
fn visit_item(&self, item: &hir::Item<'_>) {
2020-03-14 13:39:33 +01:00
// This should be kept in sync with `encode_info_for_item`.
let tcx = self.tcx;
match item.kind {
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
self.prefetch_mir(tcx.hir().local_def_id(item.hir_id))
}
hir::ItemKind::Fn(ref sig, ..) => {
let def_id = tcx.hir().local_def_id(item.hir_id);
let generics = tcx.generics_of(def_id);
let needs_inline = generics.requires_monomorphization(tcx)
|| tcx.codegen_fn_attrs(def_id).requests_inline();
if needs_inline || sig.header.constness == hir::Constness::Const {
self.prefetch_mir(def_id)
}
}
_ => (),
}
}
fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
2020-03-14 13:39:33 +01:00
// This should be kept in sync with `encode_info_for_trait_item`.
self.prefetch_mir(self.tcx.hir().local_def_id(trait_item.hir_id));
}
fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
2020-03-14 13:39:33 +01:00
// This should be kept in sync with `encode_info_for_impl_item`.
let tcx = self.tcx;
match impl_item.kind {
hir::ImplItemKind::Const(..) => {
self.prefetch_mir(tcx.hir().local_def_id(impl_item.hir_id))
}
hir::ImplItemKind::Fn(ref sig, _) => {
let def_id = tcx.hir().local_def_id(impl_item.hir_id);
let generics = tcx.generics_of(def_id);
let needs_inline = generics.requires_monomorphization(tcx)
|| tcx.codegen_fn_attrs(def_id).requests_inline();
let is_const_fn = sig.header.constness == hir::Constness::Const;
if needs_inline || is_const_fn {
self.prefetch_mir(def_id)
}
}
hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => (),
}
}
}
// NOTE(eddyb) The following comment was preserved for posterity, even
// though it's no longer relevant as EBML (which uses nested & tagged
// "documents") was replaced with a scheme that can't go out of bounds.
//
// And here we run into yet another obscure archive bug: in which metadata
// loaded from archives may have trailing garbage bytes. Awhile back one of
// our tests was failing sporadically on the macOS 64-bit builders (both nopt
// and opt) by having ebml generate an out-of-bounds panic when looking at
// metadata.
//
// Upon investigation it turned out that the metadata file inside of an rlib
// (and ar archive) was being corrupted. Some compilations would generate a
// metadata file which would end in a few extra bytes, while other
// compilations would not have these extra bytes appended to the end. These
// extra bytes were interpreted by ebml as an extra tag, so they ended up
// being interpreted causing the out-of-bounds.
//
// The root cause of why these extra bytes were appearing was never
// discovered, and in the meantime the solution we're employing is to insert
// the length of the metadata to the start of the metadata. Later on this
// will allow us to slice the metadata to the precise length that we just
// generated regardless of trailing bytes that end up in it.
pub(super) fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
// Since encoding metadata is not in a query, and nothing is cached,
// there's no need to do dep-graph tracking for any of it.
tcx.dep_graph.assert_ignored();
join(
|| encode_metadata_impl(tcx),
|| {
if tcx.sess.threads() == 1 {
return;
}
// Prefetch some queries used by metadata encoding.
2020-03-14 13:39:33 +01:00
// This is not necessary for correctness, but is only done for performance reasons.
// It can be removed if it turns out to cause trouble or be detrimental to performance.
join(
|| {
if !tcx.sess.opts.output_types.should_codegen() {
// We won't emit MIR, so don't prefetch it.
return;
}
tcx.hir().krate().par_visit_all_item_likes(&PrefetchVisitor {
tcx,
mir_keys: tcx.mir_keys(LOCAL_CRATE),
});
},
|| tcx.exported_symbols(LOCAL_CRATE),
);
},
)
.0
}
fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
let mut encoder = opaque::Encoder::new(vec![]);
encoder.emit_raw_bytes(METADATA_HEADER);
// Will be filled with the root position after encoding everything.
encoder.emit_raw_bytes(&[0, 0, 0, 0]);
let mut ecx = EncodeContext {
opaque: encoder,
tcx,
per_def: Default::default(),
lazy_state: LazyState::NoNode,
type_shorthands: Default::default(),
predicate_shorthands: Default::default(),
source_file_cache: tcx.sess.source_map().files()[0].clone(),
interpret_allocs: Default::default(),
interpret_allocs_inverse: Default::default(),
};
// Encode the rustc version string in a predictable location.
rustc_version().encode(&mut ecx).unwrap();
// Encode all the entries and extra information in the crate,
// culminating in the `CrateRoot` which points to all of it.
let root = ecx.encode_crate_root();
let mut result = ecx.opaque.into_inner();
// Encode the root position.
let header = METADATA_HEADER.len();
let pos = root.position.get();
result[header + 0] = (pos >> 24) as u8;
result[header + 1] = (pos >> 16) as u8;
result[header + 2] = (pos >> 8) as u8;
result[header + 3] = (pos >> 0) as u8;
2012-08-28 01:53:54 +02:00
EncodedMetadata { raw_data: result }
}