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

539 lines
20 KiB
Rust
Raw Normal View History

use crate::creader::{CStore, LoadedMacro};
2019-12-22 17:42:04 -05:00
use crate::foreign_modules;
2019-02-08 20:50:17 +09:00
use crate::native_libs;
use crate::rmeta::{self, encoder};
2020-04-27 23:26:11 +05:30
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
2020-10-27 15:01:03 +01:00
use rustc_data_structures::stable_map::FxHashMap;
2018-08-03 12:22:22 -06:00
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
2020-03-29 17:19:48 +02:00
use rustc_middle::hir::exports::Export;
2020-10-27 15:01:03 +01:00
use rustc_middle::middle::cstore::ForeignModule;
use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata};
2020-03-29 17:19:48 +02:00
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::utils::NativeLibKind;
use rustc_session::{Session, StableCrateId};
use rustc_span::source_map::{Span, Spanned};
2020-03-17 11:45:02 -04:00
use rustc_span::symbol::Symbol;
2019-12-22 17:42:04 -05:00
use rustc_data_structures::sync::Lrc;
2020-03-17 11:45:02 -04:00
use rustc_span::ExpnId;
2018-11-30 15:06:42 +01:00
use smallvec::SmallVec;
use std::any::Any;
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
$($name:ident => $compute:block)*) => {
pub fn provide_extern(providers: &mut Providers) {
$(fn $name<$lt>(
2019-06-14 00:48:52 +03:00
$tcx: TyCtxt<$lt>,
def_id_arg: ty::query::query_keys::$name<$lt>,
) -> ty::query::query_values::$name<$lt> {
let _prof_timer =
$tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name)));
#[allow(unused_variables)]
let ($def_id, $other) = def_id_arg.into_args();
assert!(!$def_id.is_local());
// External query providers call `crate_hash` in order to register a dependency
// on the crate metadata. The exception is `crate_hash` itself, which obviously
// doesn't need to do this (and can't, as it would cause a query cycle).
use rustc_middle::dep_graph::DepKind;
if DepKind::$name != DepKind::crate_hash && $tcx.dep_graph.is_fully_enabled() {
$tcx.ensure().crate_hash($def_id.krate);
}
let $cdata = CStore::from_tcx($tcx).get_crate_data($def_id.krate);
$compute
})*
*providers = Providers {
$($name,)*
..*providers
};
}
}
}
// small trait to work around different signature queries all being defined via
// the macro above.
trait IntoArgs {
fn into_args(self) -> (DefId, DefId);
}
impl IntoArgs for DefId {
2019-12-22 17:42:04 -05:00
fn into_args(self) -> (DefId, DefId) {
(self, self)
}
}
impl IntoArgs for CrateNum {
2019-12-22 17:42:04 -05:00
fn into_args(self) -> (DefId, DefId) {
(self.as_def_id(), self.as_def_id())
}
}
impl IntoArgs for (CrateNum, DefId) {
2019-12-22 17:42:04 -05:00
fn into_args(self) -> (DefId, DefId) {
(self.0.as_def_id(), self.1)
}
}
provide! { <'tcx> tcx, def_id, other, cdata,
type_of => { cdata.get_type(def_id.index, tcx) }
2020-03-27 20:26:20 +01:00
generics_of => { cdata.get_generics(def_id.index, tcx.sess) }
explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) }
inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) }
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
2020-06-24 19:13:44 +01:00
explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
2020-03-27 20:26:20 +01:00
trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) }
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
adt_destructor => {
let _ = cdata;
2020-10-09 17:22:25 +02:00
tcx.calculate_dtor(def_id, |_,_| Ok(()))
}
2018-11-30 15:12:41 +01:00
variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
associated_item_def_ids => {
2018-11-30 15:06:42 +01:00
let mut result = SmallVec::<[_; 8]>::new();
2017-06-14 22:49:07 -07:00
cdata.each_child_of_item(def_id.index,
|child| result.push(child.res.def_id()), tcx.sess);
2018-11-30 15:06:42 +01:00
tcx.arena.alloc_slice(&result)
}
associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
impl_polarity => { cdata.get_impl_polarity(def_id.index) }
coerce_unsized_info => {
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
})
}
2020-07-03 20:38:31 +02:00
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
2020-07-06 23:49:53 +02:00
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
2017-05-13 13:12:29 +03:00
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
2018-11-30 15:19:12 +01:00
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) }
2019-09-21 03:17:57 +00:00
asyncness => { cdata.asyncness(def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
2019-04-19 23:32:26 +03:00
static_mutability => { cdata.static_mutability(def_id.index) }
2020-01-25 19:09:23 -06:00
generator_kind => { cdata.generator_kind(def_id.index) }
2021-01-16 14:35:16 +01:00
opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
2017-04-28 10:59:57 -05:00
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
def_ident_span => {
cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
}
lookup_stability => {
cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
}
lookup_const_stability => {
cdata.get_const_stability(def_id.index).map(|s| tcx.intern_const_stability(s))
}
lookup_deprecation_entry => {
cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
}
2020-03-14 17:37:34 +01:00
item_attrs => { tcx.arena.alloc_from_iter(
cdata.get_item_attrs(def_id.index, tcx.sess)
2020-03-14 17:37:34 +01:00
) }
2020-03-14 12:06:06 +01:00
fn_arg_names => { cdata.get_fn_param_names(tcx, def_id.index) }
2018-04-15 19:41:33 -04:00
rendered_const => { cdata.get_rendered_const(def_id.index) }
2017-05-04 09:37:34 -05:00
impl_parent => { cdata.get_parent_impl(def_id.index) }
2017-05-04 08:27:48 -05:00
trait_of_item => { cdata.get_trait_of_item(def_id.index) }
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
2017-06-14 22:49:07 -07:00
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
is_panic_runtime => { cdata.root.panic_runtime }
is_compiler_builtins => { cdata.root.compiler_builtins }
has_global_allocator => { cdata.root.has_global_allocator }
has_panic_handler => { cdata.root.has_panic_handler }
is_profiler_runtime => { cdata.root.profiler_runtime }
panic_strategy => { cdata.root.panic_strategy }
2018-02-15 10:52:26 +01:00
extern_crate => {
let r = *cdata.extern_crate.lock();
r.map(|c| &*tcx.arena.alloc(c))
2018-02-15 10:52:26 +01:00
}
is_no_builtins => { cdata.root.no_builtins }
symbol_mangling_version => { cdata.root.symbol_mangling_version }
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
reachable_non_generics => {
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
.iter()
.filter_map(|&(exported_symbol, export_level)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
Some((def_id, export_level))
} else {
None
}
})
.collect();
2020-03-27 20:26:20 +01:00
reachable_non_generics
}
2018-02-27 17:11:14 +01:00
native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
foreign_modules => { cdata.get_foreign_modules(tcx) }
crate_hash => { cdata.root.hash }
crate_host_hash => { cdata.host_hash }
original_crate_name => { cdata.root.name }
extra_filename => { cdata.root.extra_filename.clone() }
implementations_of_trait => {
cdata.get_implementations_for_trait(tcx, Some(other))
}
all_trait_implementations => {
cdata.get_implementations_for_trait(tcx, None)
}
visibility => { cdata.get_visibility(def_id.index) }
2018-02-15 10:52:26 +01:00
dep_kind => {
let r = *cdata.dep_kind.lock();
r
}
crate_name => { cdata.root.name }
item_children => {
2018-11-30 22:32:16 +01:00
let mut result = SmallVec::<[_; 8]>::new();
cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
2018-11-30 22:32:16 +01:00
tcx.arena.alloc_slice(&result)
}
defined_lib_features => { cdata.get_lib_features(tcx) }
defined_lang_items => { cdata.get_lang_items(tcx) }
2020-03-27 20:26:20 +01:00
diagnostic_items => { cdata.get_diagnostic_items() }
missing_lang_items => { cdata.get_missing_lang_items(tcx) }
missing_extern_crate_item => {
2020-10-26 20:02:06 -04:00
let r = matches!(*cdata.extern_crate.borrow(), Some(extern_crate) if !extern_crate.is_direct());
2018-02-15 10:52:26 +01:00
r
}
2018-02-27 17:11:14 +01:00
used_crate_source => { Lrc::new(cdata.source.clone()) }
2017-09-20 20:42:49 +02:00
exported_symbols => {
let syms = cdata.exported_symbols(tcx);
// FIXME rust-lang/rust#64319, rust-lang/rust#64872: We want
// to block export of generics from dylibs, but we must fix
// rust-lang/rust#65890 before we can do that robustly.
2020-03-14 12:41:32 +01:00
syms
}
crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
}
pub fn provide(providers: &mut Providers) {
// FIXME(#44234) - almost all of these queries have no sub-queries and
// therefore no actual inputs, they're just reading tables calculated in
// resolve! Does this work? Unsure! That's what the issue is about
2017-06-11 21:16:26 -07:00
*providers = Providers {
2019-12-22 17:42:04 -05:00
is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
Some(
NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
) => true,
2019-12-22 17:42:04 -05:00
_ => false,
},
2020-10-26 20:02:06 -04:00
is_statically_included_foreign_item: |tcx, id| {
matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
},
native_library_kind: |tcx, id| {
tcx.native_libraries(id.krate)
.iter()
.filter(|lib| native_libs::relevant_lib(&tcx.sess, lib))
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
.find(|lib| {
let fm_id = match lib.foreign_module {
Some(id) => id,
None => return false,
};
2020-10-27 15:01:03 +01:00
let map = tcx.foreign_modules(id.krate);
map.get(&fm_id)
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
.expect("failed to find foreign module")
.foreign_items
.contains(&id)
})
.map(|l| l.kind)
},
native_libraries: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
2018-02-27 17:11:14 +01:00
Lrc::new(native_libs::collect(tcx))
},
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
foreign_modules: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
2020-10-27 15:01:03 +01:00
let modules: FxHashMap<DefId, ForeignModule> =
foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect();
Lrc::new(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 14:28:17 -08:00
},
// Returns a map from a sufficiently visible external item (i.e., an
// external item that is visible from at least one local module) to a
// sufficiently visible parent (considering modules that re-export the
// external item to be parents).
2021-05-11 14:16:48 +02:00
visible_parent_map: |tcx, ()| {
use std::collections::hash_map::Entry;
2019-12-22 17:42:04 -05:00
use std::collections::vec_deque::VecDeque;
let mut visible_parent_map: DefIdMap<DefId> = Default::default();
// Issue 46112: We want the map to prefer the shortest
// paths when reporting the path to an item. Therefore we
// build up the map via a breadth-first search (BFS),
// which naturally yields minimal-length paths.
//
// Note that it needs to be a BFS over the whole forest of
// crates, not just each individual crate; otherwise you
// only get paths that are locally minimal with respect to
// whatever crate we happened to encounter first in this
// traversal, but not globally minimal across all crates.
let bfs_queue = &mut VecDeque::new();
// Preferring shortest paths alone does not guarantee a
// deterministic result; so sort by crate num to avoid
// hashtable iteration non-determinism. This only makes
// things as deterministic as crate-nums assignment is,
// which is to say, its not deterministic in general. But
// we believe that libstd is consistently assigned crate
// num 1, so it should be enough to resolve #46112.
let mut crates: Vec<CrateNum> = (*tcx.crates()).to_owned();
crates.sort();
for &cnum in crates.iter() {
// Ignore crates without a corresponding local `extern crate` item.
if tcx.missing_extern_crate_item(cnum) {
2019-12-22 17:42:04 -05:00
continue;
}
2019-12-22 17:42:04 -05:00
bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
}
// (restrict scope of mutable-borrow of `visible_parent_map`)
{
let visible_parent_map = &mut visible_parent_map;
let mut add_child =
|bfs_queue: &mut VecDeque<_>, child: &Export<hir::HirId>, parent: DefId| {
if child.vis != ty::Visibility::Public {
return;
}
if let Some(child) = child.res.opt_def_id() {
match visible_parent_map.entry(child) {
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
// that it is mapped to a parent in `cnum`.
2021-05-11 14:16:48 +02:00
if child.is_local() && entry.get().is_local() {
entry.insert(parent);
}
}
Entry::Vacant(entry) => {
2019-05-20 11:46:44 -07:00
entry.insert(parent);
bfs_queue.push_back(child);
2019-05-20 11:46:44 -07:00
}
}
}
};
while let Some(def) = bfs_queue.pop_front() {
for child in tcx.item_children(def).iter() {
add_child(bfs_queue, child, def);
}
}
}
2020-03-27 20:26:20 +01:00
visible_parent_map
},
2021-05-11 11:26:52 +02:00
dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
has_global_allocator: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
CStore::from_tcx(tcx).has_global_allocator()
},
2021-05-11 14:50:54 +02:00
postorder_cnums: |tcx, ()| {
tcx.arena
.alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
},
2017-06-11 21:16:26 -07:00
..*providers
};
}
impl CStore {
pub fn struct_field_names_untracked(&self, def: DefId, sess: &Session) -> Vec<Spanned<Symbol>> {
self.get_crate_data(def.krate).get_struct_field_names(def.index, sess)
2015-11-20 17:46:39 +02:00
}
pub fn struct_field_visibilities_untracked(&self, def: DefId) -> Vec<Visibility> {
self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
}
pub fn ctor_def_id_and_kind_untracked(&self, def: DefId) -> Option<(DefId, CtorKind)> {
self.get_crate_data(def.krate).get_ctor_def_id(def.index).map(|ctor_def_id| {
(ctor_def_id, self.get_crate_data(def.krate).get_ctor_kind(def.index))
})
}
pub fn visibility_untracked(&self, def: DefId) -> Visibility {
self.get_crate_data(def.krate).get_visibility(def.index)
}
2019-04-03 09:07:45 +02:00
pub fn item_children_untracked(
&self,
def_id: DefId,
2019-12-22 17:42:04 -05:00
sess: &Session,
) -> Vec<Export<hir::HirId>> {
2015-11-20 17:46:39 +02:00
let mut result = vec![];
2019-12-22 17:42:04 -05:00
self.get_crate_data(def_id.krate).each_child_of_item(
def_id.index,
|child| result.push(child),
sess,
);
2015-11-20 17:46:39 +02:00
result
}
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
let _prof_timer = sess.prof.generic_activity("metadata_load_macro");
let data = self.get_crate_data(id.krate);
if data.root.is_proc_macro_crate() {
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
return LoadedMacro::ProcMacro(data.load_proc_macro(id, sess));
}
let span = data.get_span(id.index, sess);
2016-10-28 06:52:45 +00:00
let attrs = data.get_item_attrs(id.index, sess).collect();
2016-10-28 06:52:45 +00:00
2020-03-17 11:45:02 -04:00
let ident = data.item_ident(id.index, sess);
2016-10-28 06:52:45 +00:00
2019-12-22 17:42:04 -05:00
LoadedMacro::MacroDef(
ast::Item {
ident,
2019-12-22 17:42:04 -05:00
id: ast::DUMMY_NODE_ID,
span,
attrs,
kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)),
vis: ast::Visibility {
span: span.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
2019-12-22 17:42:04 -05:00
tokens: None,
},
data.root.edition,
)
2016-10-28 06:52:45 +00:00
}
pub fn associated_item_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::AssocItem {
self.get_crate_data(def.krate).get_associated_item(def.index, sess)
}
pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
self.get_crate_data(cnum).source.clone()
}
pub fn get_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
self.get_crate_data(def_id.krate).get_span(def_id.index, sess)
}
pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
}
2020-03-17 11:45:02 -04:00
pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
}
2020-12-02 23:39:05 +03:00
2021-02-23 15:12:28 +00:00
pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
}
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
pub fn get_proc_macro_quoted_span_untracked(
&self,
cnum: CrateNum,
id: usize,
sess: &Session,
) -> Span {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}
}
impl CrateStore for CStore {
fn as_any(&self) -> &dyn Any {
self
}
2019-12-22 17:42:04 -05:00
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol {
self.get_crate_data(cnum).root.name
}
fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool {
self.get_crate_data(cnum).private_dep
}
fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId {
self.get_crate_data(cnum).root.stable_crate_id
}
2019-12-22 17:42:04 -05:00
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh {
self.get_crate_data(cnum).root.hash
}
/// Returns the `DefKey` for a given `DefId`. This indicates the
/// parent `DefId` as well as some idea of what kind of data the
/// `DefId` refers to.
fn def_key(&self, def: DefId) -> DefKey {
self.get_crate_data(def.krate).def_key(def.index)
}
fn def_kind(&self, def: DefId) -> DefKind {
self.get_crate_data(def.krate).def_kind(def.index)
}
fn def_path(&self, def: DefId) -> DefPath {
self.get_crate_data(def.krate).def_path(def.index)
}
fn def_path_hash(&self, def: DefId) -> DefPathHash {
self.get_crate_data(def.krate).def_path_hash(def.index)
}
// See `CrateMetadataRef::def_path_hash_to_def_id` for more details
fn def_path_hash_to_def_id(
&self,
cnum: CrateNum,
index_guess: u32,
hash: DefPathHash,
) -> Option<DefId> {
self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash)
}
2019-12-22 17:42:04 -05:00
fn crates_untracked(&self) -> Vec<CrateNum> {
let mut result = vec![];
self.iter_crate_data(|cnum, _| result.push(cnum));
result
}
2019-06-21 20:27:44 +02:00
fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata {
encoder::encode_metadata(tcx)
2015-11-21 01:08:09 +02:00
}
fn metadata_encoding_version(&self) -> &[u8] {
rmeta::METADATA_HEADER
}
fn allocator_kind(&self) -> Option<AllocatorKind> {
self.allocator_kind()
}
}