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

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

602 lines
22 KiB
Rust
Raw Normal View History

2022-02-17 21:33:23 +01:00
use super::LazyQueryDecodable;
use crate::creader::{CStore, LoadedMacro};
2019-02-08 20:50:17 +09:00
use crate::foreign_modules;
use crate::native_libs;
2020-04-27 23:26:11 +05:30
use rustc_ast as ast;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_middle::metadata::ModChild;
2020-03-29 17:19:48 +02:00
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore};
use rustc_session::utils::NativeLibKind;
use rustc_session::{Session, StableCrateId};
use rustc_span::hygiene::{ExpnHash, ExpnId};
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, Symbol};
2018-02-27 17:11:14 +01:00
use rustc_data_structures::sync::Lrc;
2018-11-30 15:06:42 +01:00
use smallvec::SmallVec;
use std::any::Any;
2022-02-17 21:33:23 +01:00
macro_rules! provide_one {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => {
provide_one! {
<$lt> $tcx, $def_id, $other, $cdata, $name => {
$cdata.root.tables.$name.get($cdata, $def_id.index).decode_query(
$cdata,
$tcx,
|| panic!("{:?} does not have a {:?}", $def_id, stringify!($name)),
)
}
}
};
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => {
fn $name<$lt>(
$tcx: TyCtxt<$lt>,
def_id_arg: ty::query::query_keys::$name<$lt>,
) -> ty::query::query_values::$name<$lt> {
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
}
};
}
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
2022-02-17 21:33:23 +01:00
$($name:ident => { $($compute:tt)* })*) => {
pub fn provide_extern(providers: &mut ExternProviders) {
2022-02-17 21:33:23 +01:00
$(provide_one! {
<$lt> $tcx, $def_id, $other, $cdata, $name => { $($compute)* }
})*
*providers = ExternProviders {
$($name,)*
..*providers
};
}
}
}
// small trait to work around different signature queries all being defined via
// the macro above.
trait IntoArgs {
type Other;
fn into_args(self) -> (DefId, Self::Other);
}
impl IntoArgs for DefId {
type Other = ();
fn into_args(self) -> (DefId, ()) {
(self, ())
}
}
impl IntoArgs for CrateNum {
type Other = ();
fn into_args(self) -> (DefId, ()) {
(self.as_def_id(), ())
}
}
impl IntoArgs for (CrateNum, DefId) {
type Other = DefId;
fn into_args(self) -> (DefId, DefId) {
(self.0.as_def_id(), self.1)
}
}
impl<'tcx> IntoArgs for ty::InstanceDef<'tcx> {
type Other = ();
fn into_args(self) -> (DefId, ()) {
(self.def_id(), ())
}
}
impl IntoArgs for (CrateNum, SimplifiedType) {
type Other = SimplifiedType;
fn into_args(self) -> (DefId, SimplifiedType) {
(self.0.as_def_id(), self.1)
}
}
provide! { <'tcx> tcx, def_id, other, cdata,
2022-02-17 21:33:23 +01:00
explicit_item_bounds => { table }
explicit_predicates_of => { table }
generics_of => { table }
inferred_outlives_of => { table }
super_predicates_of => { table }
type_of => { table }
variances_of => { table }
fn_sig => { table }
codegen_fn_attrs => { table }
2022-02-17 21:33:23 +01:00
impl_trait_ref => { table }
const_param_default => { table }
thir_abstract_const => { table }
optimized_mir => { table }
mir_for_ctfe => { table }
promoted_mir => { table }
def_span => { table }
def_ident_span => { table }
lookup_stability => { table }
lookup_const_stability => { table }
lookup_deprecation_entry => { table }
visibility => { table }
unused_generic_params => { table }
opt_def_kind => { table }
2022-02-17 22:00:03 +01:00
impl_parent => { table }
impl_polarity => { table }
impl_defaultness => { table }
impl_constness => { table }
coerce_unsized_info => { table }
2022-02-18 18:53:47 +01:00
mir_const_qualif => { table }
2022-02-18 19:09:02 +01:00
rendered_const => { table }
2022-02-18 19:15:48 +01:00
asyncness => { table }
2022-02-18 19:23:58 +01:00
fn_arg_names => { table }
2022-02-18 19:34:24 +01:00
generator_kind => { table }
2022-03-10 19:07:27 +01:00
trait_def => { table }
2022-02-17 21:33:23 +01:00
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(()))
}
associated_item_def_ids => {
tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess))
}
associated_item => { cdata.get_associated_item(def_id.index) }
2018-11-30 15:19:12 +01:00
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
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) }
2021-05-11 22:06:07 +02:00
is_private_dep => { cdata.private_dep }
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 }
panic_in_drop_strategy => { cdata.root.panic_in_drop_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 }
reachable_non_generics => {
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
.iter()
.filter_map(|&(exported_symbol, export_info)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
Some((def_id, export_info))
} else {
None
}
})
.collect();
2020-03-27 20:26:20 +01:00
reachable_non_generics
}
native_libraries => { cdata.get_native_libraries(tcx.sess).collect() }
foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() }
crate_hash => { cdata.root.hash }
crate_host_hash => { cdata.host_hash }
crate_name => { cdata.root.name }
extra_filename => { cdata.root.extra_filename.clone() }
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
2018-02-15 10:52:26 +01:00
dep_kind => {
let r = *cdata.dep_kind.lock();
r
}
module_children => {
2018-11-30 22:32:16 +01:00
let mut result = SmallVec::<[_; 8]>::new();
cdata.for_each_module_child(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) }
is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
2022-03-18 17:02:32 +01:00
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
}
used_crate_source => { Lrc::clone(&cdata.source) }
debugger_visualizers => { cdata.get_debugger_visualizers() }
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) }
generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
}
pub(in crate::rmeta) 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 {
2021-06-06 11:30:08 +02:00
allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
Some(
NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
) => true,
_ => 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 { .. }))
},
2021-05-11 22:06:07 +02:00
is_private_dep: |_tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
false
},
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| {
2022-02-19 00:48:49 +01:00
let Some(fm_id) = lib.foreign_module else {
return false;
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
};
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);
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);
foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
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;
use std::collections::vec_deque::VecDeque;
let mut visible_parent_map: DefIdMap<DefId> = Default::default();
// This is a secondary visible_parent_map, storing the DefId of parents that re-export
// the child as `_`. Since we prefer parents that don't do this, merge this map at the
// end, only if we're missing any keys from the former.
let mut fallback_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();
2021-09-17 09:13:16 +02:00
for &cnum in tcx.crates(()) {
// Ignore crates without a corresponding local `extern crate` item.
if tcx.missing_extern_crate_item(cnum) {
continue;
}
bfs_queue.push_back(cnum.as_def_id());
}
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
if !child.vis.is_public() {
2021-09-17 09:13:16 +02:00
return;
}
if let Some(def_id) = child.res.opt_def_id() {
if child.ident.name == kw::Underscore {
fallback_map.insert(def_id, parent);
return;
}
match visible_parent_map.entry(def_id) {
2021-09-17 09:13:16 +02:00
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
// that it is mapped to a parent in `cnum`.
if def_id.is_local() && entry.get().is_local() {
entry.insert(parent);
}
}
2021-09-17 09:13:16 +02:00
Entry::Vacant(entry) => {
entry.insert(parent);
if matches!(
child.res,
Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _)
) {
bfs_queue.push_back(def_id);
}
2021-09-17 09:13:16 +02:00
}
}
2021-09-17 09:13:16 +02:00
}
};
2021-09-17 09:13:16 +02:00
while let Some(def) = bfs_queue.pop_front() {
for child in tcx.module_children(def).iter() {
2021-09-17 09:13:16 +02:00
add_child(bfs_queue, child, def);
}
}
// Fill in any missing entries with the (less preferable) path ending in `::_`.
// We still use this path in a diagnostic that suggests importing `::*`.
for (child, parent) in fallback_map {
visible_parent_map.entry(child).or_insert(parent);
}
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))
},
crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()),
2017-06-11 21:16:26 -07:00
..*providers
};
}
impl CStore {
pub fn struct_field_names_untracked<'a>(
&'a self,
def: DefId,
sess: &'a Session,
) -> impl Iterator<Item = Spanned<Symbol>> + 'a {
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,
) -> impl Iterator<Item = 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_and_kind(def.index)
}
pub fn visibility_untracked(&self, def: DefId) -> Visibility {
self.get_crate_data(def.krate).get_visibility(def.index)
}
pub fn module_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ModChild> {
2015-11-20 17:46:39 +02:00
let mut result = vec![];
self.get_crate_data(def_id.krate).for_each_module_child(
2017-06-07 16:17:11 +02:00
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() {
return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess));
}
let span = data.get_span(id.index, sess);
2016-10-28 06:52:45 +00:00
LoadedMacro::MacroDef(
ast::Item {
ident: data.item_ident(id.index, sess),
2016-10-28 06:52:45 +00:00
id: ast::DUMMY_NODE_ID,
span,
attrs: data.get_item_attrs(id.index, sess).collect(),
kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)),
vis: ast::Visibility {
span: span.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
tokens: None,
},
data.root.edition,
)
2016-10-28 06:52:45 +00:00
}
pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool {
self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index)
}
pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc<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 def_kind(&self, def: DefId) -> DefKind {
self.get_crate_data(def.krate).def_kind(def.index)
}
pub fn crates_untracked(&self) -> impl Iterator<Item = CrateNum> + '_ {
self.iter_crate_data().map(|(cnum, _)| cnum)
}
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
/// Only public-facing way to traverse all the definitions in a non-local crate.
/// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>.
/// See <https://github.com/rust-lang/rust/pull/85889> for context.
pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
self.get_crate_data(cnum).num_def_ids()
}
pub fn item_attrs_untracked<'a>(
&'a self,
def_id: DefId,
sess: &'a Session,
) -> impl Iterator<Item = ast::Attribute> + 'a {
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess)
2021-02-23 15:12:28 +00:00
}
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)
}
/// Decodes all traits in the crate (for rustdoc).
pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
self.get_crate_data(cnum).get_traits()
}
/// Decodes all trait impls in the crate (for rustdoc).
pub fn trait_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ {
self.get_crate_data(cnum).get_trait_impls()
}
/// Decodes all inherent impls in the crate (for rustdoc).
pub fn inherent_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> impl Iterator<Item = (DefId, DefId)> + '_ {
self.get_crate_data(cnum).get_inherent_impls()
}
2022-03-18 17:02:32 +01:00
/// Decodes all incoherent inherent impls in the crate (for rustdoc).
pub fn incoherent_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> impl Iterator<Item = DefId> + '_ {
self.get_crate_data(cnum).get_all_incoherent_impls()
}
pub fn associated_item_def_ids_untracked<'a>(
&'a self,
def_id: DefId,
sess: &'a Session,
) -> impl Iterator<Item = DefId> + 'a {
self.get_crate_data(def_id.krate).get_associated_item_def_ids(def_id.index, sess)
}
pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index)
}
}
impl CrateStore for CStore {
fn as_any(&self) -> &dyn Any {
self
}
fn crate_name(&self, cnum: CrateNum) -> Symbol {
self.get_crate_data(cnum).root.name
}
fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId {
self.get_crate_data(cnum).root.stable_crate_id
}
fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
self.stable_crate_ids[&stable_crate_id]
}
/// 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_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)
}
fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId {
let def_index = self.get_crate_data(cnum).def_path_hash_to_def_index(hash);
DefId { krate: cnum, index: def_index }
}
2021-10-02 17:35:27 +02:00
fn expn_hash_to_expn_id(
&self,
sess: &Session,
cnum: CrateNum,
index_guess: u32,
hash: ExpnHash,
) -> ExpnId {
self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash)
}
fn import_source_files(&self, sess: &Session, cnum: CrateNum) {
self.get_crate_data(cnum).imported_source_files(sess);
}
}