EII collection queries
EII collection queries
This commit is contained in:
parent
33df6ccb21
commit
1cbdaf246b
14 changed files with 332 additions and 17 deletions
|
|
@ -1061,6 +1061,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
parallel!(
|
||||
{
|
||||
sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(()));
|
||||
sess.time("check_externally_implementable_items", || {
|
||||
tcx.ensure_ok().check_externally_implementable_items(())
|
||||
});
|
||||
|
||||
sess.time("looking_for_derive_registrar", || {
|
||||
tcx.ensure_ok().proc_macro_decls_static(())
|
||||
|
|
|
|||
48
compiler/rustc_metadata/src/eii.rs
Normal file
48
compiler/rustc_metadata/src/eii.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_middle::query::LocalCrate;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
// basically the map below but flattened out
|
||||
pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>));
|
||||
|
||||
pub(crate) type EiiMap = FxIndexMap<
|
||||
DefId, // the defid of the macro that declared the eii
|
||||
(
|
||||
// the corresponding declaration
|
||||
EiiDecl,
|
||||
// all the given implementations, indexed by defid.
|
||||
// We expect there to be only one, but collect them all to give errors if there are more
|
||||
// (or if there are none) in the final crate we build.
|
||||
FxIndexMap<DefId, EiiImpl>,
|
||||
),
|
||||
>;
|
||||
|
||||
pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap {
|
||||
let mut eiis = EiiMap::default();
|
||||
|
||||
// iterate over all items in the current crate
|
||||
// FIXME(speed up)
|
||||
for id in tcx.hir_crate_items(()).definitions() {
|
||||
for i in
|
||||
find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten()
|
||||
{
|
||||
eiis.entry(i.eii_macro)
|
||||
.or_insert_with(|| {
|
||||
// find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal)
|
||||
(find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d).unwrap(), Default::default())
|
||||
}).1.insert(id.into(), *i);
|
||||
}
|
||||
|
||||
// if we find a new declaration, add it to the list without a known implementation
|
||||
if let Some(decl) =
|
||||
find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiExternTarget(d) => *d)
|
||||
{
|
||||
eiis.entry(id.into()).or_insert((decl, Default::default()));
|
||||
}
|
||||
}
|
||||
|
||||
eiis
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
pub use rmeta::provide;
|
||||
|
||||
mod dependency_format;
|
||||
mod eii;
|
||||
mod foreign_modules;
|
||||
mod native_libs;
|
||||
mod rmeta;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use rustc_span::{
|
|||
use tracing::debug;
|
||||
|
||||
use crate::creader::CStore;
|
||||
use crate::eii::EiiMapEncodedKeyValue;
|
||||
use crate::rmeta::table::IsDefault;
|
||||
use crate::rmeta::*;
|
||||
|
||||
|
|
@ -1487,6 +1488,13 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_externally_implementable_items(
|
||||
self,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> impl Iterator<Item = EiiMapEncodedKeyValue> {
|
||||
self.root.externally_implementable_items.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_missing_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] {
|
||||
tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode((self, tcx)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use super::{Decodable, DecodeIterator};
|
|||
use crate::creader::{CStore, LoadedMacro};
|
||||
use crate::rmeta::AttrFlags;
|
||||
use crate::rmeta::table::IsDefault;
|
||||
use crate::{foreign_modules, native_libs};
|
||||
use crate::{eii, foreign_modules, native_libs};
|
||||
|
||||
trait ProcessQueryValue<'tcx, T> {
|
||||
fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T;
|
||||
|
|
@ -330,9 +330,22 @@ provide! { tcx, def_id, other, cdata,
|
|||
is_private_dep => { cdata.private_dep }
|
||||
is_panic_runtime => { cdata.root.panic_runtime }
|
||||
is_compiler_builtins => { cdata.root.compiler_builtins }
|
||||
|
||||
// FIXME: to be replaced with externally_implementable_items below
|
||||
has_global_allocator => { cdata.root.has_global_allocator }
|
||||
// FIXME: to be replaced with externally_implementable_items below
|
||||
has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
|
||||
// FIXME: to be replaced with externally_implementable_items below
|
||||
has_panic_handler => { cdata.root.has_panic_handler }
|
||||
|
||||
externally_implementable_items => {
|
||||
cdata.get_externally_implementable_items(tcx)
|
||||
.map(|(decl_did, (decl, impls))| (
|
||||
decl_did,
|
||||
(decl, impls.into_iter().collect())
|
||||
)).collect()
|
||||
}
|
||||
|
||||
is_profiler_runtime => { cdata.root.profiler_runtime }
|
||||
required_panic_strategy => { cdata.root.required_panic_strategy }
|
||||
panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
|
||||
|
|
@ -430,6 +443,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
|||
},
|
||||
native_libraries: native_libs::collect,
|
||||
foreign_modules: foreign_modules::collect,
|
||||
externally_implementable_items: eii::collect,
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use rustc_span::{
|
|||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::eii::EiiMapEncodedKeyValue;
|
||||
use crate::errors::{FailCreateFileEncoder, FailWriteFile};
|
||||
use crate::rmeta::*;
|
||||
|
||||
|
|
@ -620,6 +621,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
// We have already encoded some things. Get their combined size from the current position.
|
||||
stats.push(("preamble", self.position()));
|
||||
|
||||
let externally_implementable_items = stat!("externally-implementable-items", || self
|
||||
.encode_externally_implementable_items());
|
||||
|
||||
let (crate_deps, dylib_dependency_formats) =
|
||||
stat!("dep", || (self.encode_crate_deps(), self.encode_dylib_dependency_formats()));
|
||||
|
||||
|
|
@ -738,6 +742,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
attrs,
|
||||
sym::default_lib_allocator,
|
||||
),
|
||||
externally_implementable_items,
|
||||
proc_macro_data,
|
||||
debugger_visualizers,
|
||||
compiler_builtins: ast::attr::contains_name(attrs, sym::compiler_builtins),
|
||||
|
|
@ -1649,6 +1654,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_externally_implementable_items(&mut self) -> LazyArray<EiiMapEncodedKeyValue> {
|
||||
empty_proc_macro!(self);
|
||||
let externally_implementable_items = self.tcx.externally_implementable_items(LOCAL_CRATE);
|
||||
|
||||
self.lazy_array(externally_implementable_items.iter().map(|(decl_did, (decl, impls))| {
|
||||
(*decl_did, (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect()))
|
||||
}))
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn encode_info_for_adt(&mut self, local_def_id: LocalDefId) {
|
||||
let def_id = local_def_id.to_def_id();
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ use table::TableBuilder;
|
|||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::creader::CrateMetadataRef;
|
||||
use crate::eii::EiiMapEncodedKeyValue;
|
||||
|
||||
mod decoder;
|
||||
mod def_path_hash_map;
|
||||
|
|
@ -250,6 +251,7 @@ pub(crate) struct CrateRoot {
|
|||
has_alloc_error_handler: bool,
|
||||
has_panic_handler: bool,
|
||||
has_default_lib_allocator: bool,
|
||||
externally_implementable_items: LazyArray<EiiMapEncodedKeyValue>,
|
||||
|
||||
crate_deps: LazyArray<CrateDep>,
|
||||
dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ trivially_parameterized_over_tcx! {
|
|||
rustc_hir::Safety,
|
||||
rustc_hir::Stability,
|
||||
rustc_hir::attrs::Deprecation,
|
||||
rustc_hir::attrs::EiiDecl,
|
||||
rustc_hir::attrs::EiiImpl,
|
||||
rustc_hir::attrs::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
|
||||
rustc_hir::def::DefKind,
|
||||
rustc_hir::def::DocLinkResMap,
|
||||
|
|
|
|||
|
|
@ -296,6 +296,8 @@ trivial! {
|
|||
rustc_ast::expand::allocator::AllocatorKind,
|
||||
rustc_hir::DefaultBodyStability,
|
||||
rustc_hir::attrs::Deprecation,
|
||||
rustc_hir::attrs::EiiDecl,
|
||||
rustc_hir::attrs::EiiImpl,
|
||||
rustc_data_structures::svh::Svh,
|
||||
rustc_errors::ErrorGuaranteed,
|
||||
rustc_hir::Constness,
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ use rustc_data_structures::steal::Steal;
|
|||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::attrs::StrippedCfgItem;
|
||||
use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
|
||||
use rustc_hir::def::{DefKind, DocLinkResMap};
|
||||
use rustc_hir::def_id::{
|
||||
CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
|
||||
|
|
@ -2753,6 +2753,17 @@ rustc_queries! {
|
|||
desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) }
|
||||
feedable
|
||||
}
|
||||
|
||||
query check_externally_implementable_items(_: ()) {
|
||||
desc { "check externally implementable items" }
|
||||
}
|
||||
|
||||
/// Returns a list of all `externally implementable items` crate.
|
||||
query externally_implementable_items(_: CrateNum) -> &'tcx FxIndexMap<DefId, (EiiDecl, FxIndexMap<DefId, EiiImpl>)> {
|
||||
arena_cache
|
||||
desc { "looking up the externally implementable items of a crate" }
|
||||
separate_provide_extern
|
||||
}
|
||||
}
|
||||
|
||||
rustc_with_all_queries! { define_callbacks! }
|
||||
|
|
|
|||
|
|
@ -164,6 +164,17 @@ passes_duplicate_diagnostic_item_in_crate =
|
|||
duplicate diagnostic item in crate `{$crate_name}`: `{$name}`
|
||||
.note = the diagnostic item is first defined in crate `{$orig_crate_name}`
|
||||
|
||||
passes_duplicate_eii_impls =
|
||||
multiple implementations of `#[{$name}]`
|
||||
.first = first implemented here in crate `{$first_crate}`
|
||||
.second = also implemented here in crate `{$second_crate}`
|
||||
.note = in addition to these two, { $num_additional_crates ->
|
||||
[one] another implementation was found in crate {$additional_crate_names}
|
||||
*[other] more implementations were also found in the following crates: {$additional_crate_names}
|
||||
}
|
||||
|
||||
.help = an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict
|
||||
|
||||
passes_duplicate_feature_err =
|
||||
the feature `{$feature}` has already been enabled
|
||||
|
||||
|
|
@ -197,6 +208,22 @@ passes_duplicate_lang_item_crate_depends =
|
|||
.first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
|
||||
.second_definition_path = second definition in `{$crate_name}` loaded from {$path}
|
||||
|
||||
passes_eii_fn_with_track_caller =
|
||||
`#[{$name}]` is not allowed to have `#[track_caller]`
|
||||
.label = `#[{$name}]` is not allowed to have `#[track_caller]`
|
||||
|
||||
passes_eii_impl_not_function =
|
||||
`eii_macro_for` is only valid on functions
|
||||
|
||||
passes_eii_impl_requires_unsafe =
|
||||
`#[{$name}]` is unsafe to implement
|
||||
passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
||||
passes_eii_without_impl =
|
||||
`#[{$name}]` required, but not found
|
||||
.label = expected because `#[{$name}]` was declared here in crate `{$decl_crate_name}`
|
||||
.help = expected at least one implementation in crate `{$current_crate_name}` or any of its dependencies
|
||||
|
||||
passes_enum_variant_same_name =
|
||||
it is impossible to refer to the {$dead_descr} `{$dead_name}` because it is shadowed by this enum variant with the same name
|
||||
|
||||
|
|
@ -590,18 +617,3 @@ passes_useless_stability =
|
|||
this stability annotation is useless
|
||||
.label = useless stability annotation
|
||||
.item = the stability attribute annotates this item
|
||||
|
||||
passes_eii_fn_with_target_feature =
|
||||
`#[{$name}]` is not allowed to have `#[target_feature]`
|
||||
.label = `#[{$name}]` is not allowed to have `#[target_feature]`
|
||||
|
||||
passes_eii_fn_with_track_caller =
|
||||
`#[{$name}]` is not allowed to have `#[track_caller]`
|
||||
.label = `#[{$name}]` is not allowed to have `#[track_caller]`
|
||||
|
||||
passes_eii_impl_not_function =
|
||||
`eii_macro_for` is only valid on functions
|
||||
|
||||
passes_eii_impl_requires_unsafe =
|
||||
`#[{$name}]` is unsafe to implement
|
||||
passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
|
|
|||
158
compiler/rustc_passes/src/eii.rs
Normal file
158
compiler/rustc_passes/src/eii.rs
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
//! Checks necessary for externally implementable items:
|
||||
//! Are all items implemented etc.?
|
||||
|
||||
use std::iter;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::attrs::{EiiDecl, EiiImpl};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::CrateType;
|
||||
|
||||
use crate::errors::{DuplicateEiiImpls, EiiWithoutImpl};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum CheckingMode {
|
||||
CheckDuplicates,
|
||||
CheckExistence,
|
||||
}
|
||||
|
||||
fn get_checking_mode(tcx: TyCtxt<'_>) -> CheckingMode {
|
||||
// if any of the crate types is not rlib or dylib, we must check for existence.
|
||||
if tcx.crate_types().iter().any(|i| !matches!(i, CrateType::Rlib | CrateType::Dylib)) {
|
||||
CheckingMode::CheckExistence
|
||||
} else {
|
||||
CheckingMode::CheckDuplicates
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for a given crate, what EIIs need to be generated in it.
|
||||
/// This is usually a small subset of all EIIs.
|
||||
///
|
||||
/// EII implementations come in two varieties: explicit and default.
|
||||
/// This query is called once for every crate, to check whether there aren't any duplicate explicit implementations.
|
||||
/// A duplicate may be caused by an implementation in the current crate,
|
||||
/// though it's also entirely possible that the source is two dependencies with an explicit implementation.
|
||||
/// Those work fine on their own but the combination of the two is a conflict.
|
||||
///
|
||||
/// However, if the current crate is a "root" crate, one that generates a final artifact like a binary,
|
||||
/// then we check one more thing, namely that every EII actually has an implementation, either default or not.
|
||||
/// If one EII has no implementation, that's an error at that point.
|
||||
///
|
||||
/// These two behaviors are implemented using `CheckingMode`.
|
||||
pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) {
|
||||
let checking_mode = get_checking_mode(tcx);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FoundImpl {
|
||||
imp: EiiImpl,
|
||||
impl_crate: CrateNum,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FoundEii {
|
||||
decl: EiiDecl,
|
||||
decl_crate: CrateNum,
|
||||
impls: FxIndexMap<DefId, FoundImpl>,
|
||||
}
|
||||
|
||||
let mut eiis = FxIndexMap::<DefId, FoundEii>::default();
|
||||
|
||||
// collect all the EII declarations, and possibly implementations from all descendent crates
|
||||
for &cnum in tcx.crates(()).iter().chain(iter::once(&LOCAL_CRATE)) {
|
||||
// get the eiis for the crate we're currently looking at
|
||||
let crate_eiis = tcx.externally_implementable_items(cnum);
|
||||
|
||||
// update or insert the corresponding entries
|
||||
for (did, (decl, impls)) in crate_eiis {
|
||||
eiis.entry(*did)
|
||||
.or_insert_with(|| FoundEii {
|
||||
decl: *decl,
|
||||
decl_crate: cnum,
|
||||
impls: Default::default(),
|
||||
})
|
||||
.impls
|
||||
.extend(
|
||||
impls
|
||||
.into_iter()
|
||||
.map(|(did, i)| (*did, FoundImpl { imp: *i, impl_crate: cnum })),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// now we have all eiis! For each of them, choose one we want to actually generate.
|
||||
for (decl_did, FoundEii { decl, decl_crate, impls }) in eiis {
|
||||
let mut default_impls = Vec::new();
|
||||
let mut explicit_impls = Vec::new();
|
||||
|
||||
for (impl_did, FoundImpl { imp, impl_crate }) in impls {
|
||||
if imp.is_default {
|
||||
default_impls.push((impl_did, impl_crate));
|
||||
} else {
|
||||
explicit_impls.push((impl_did, impl_crate));
|
||||
}
|
||||
}
|
||||
|
||||
// more than one explicit implementation (across all crates)
|
||||
// is instantly an error.
|
||||
if explicit_impls.len() > 1 {
|
||||
tcx.dcx().emit_err(DuplicateEiiImpls {
|
||||
name: tcx.item_name(decl_did),
|
||||
first_span: tcx.def_span(explicit_impls[0].0),
|
||||
first_crate: tcx.crate_name(explicit_impls[0].1),
|
||||
second_span: tcx.def_span(explicit_impls[1].0),
|
||||
second_crate: tcx.crate_name(explicit_impls[1].1),
|
||||
|
||||
help: (),
|
||||
|
||||
additional_crates: (explicit_impls.len() > 2).then_some(()),
|
||||
num_additional_crates: explicit_impls.len() - 2,
|
||||
additional_crate_names: explicit_impls[2..]
|
||||
.iter()
|
||||
.map(|i| format!("`{}`", tcx.crate_name(i.1)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
if default_impls.len() > 1 {
|
||||
panic!("multiple not supported right now");
|
||||
}
|
||||
|
||||
let (local_impl, is_default) =
|
||||
// note, for a single crate we never need to generate both a default and an explicit implementation.
|
||||
// In that case, generating the explicit implementation is enough!
|
||||
match (checking_mode, explicit_impls.first(), default_impls.first()) {
|
||||
// If we find an explicit implementation, it's instantly the chosen implementation.
|
||||
(_, Some((explicit, _)), _) => (explicit, false),
|
||||
// if we find a default implementation, we can emit it but the alias should be weak
|
||||
(_, _, Some((deflt, _))) => (deflt, true),
|
||||
|
||||
// if we find no explicit implementation,
|
||||
// that's fine if we're only checking for duplicates.
|
||||
// The existence will be checked somewhere else in a crate downstream.
|
||||
(CheckingMode::CheckDuplicates, None, _) => continue,
|
||||
|
||||
// We have a target to generate, but no impl to put in it. error!
|
||||
(CheckingMode::CheckExistence, None, None) => {
|
||||
tcx.dcx().emit_err(EiiWithoutImpl {
|
||||
current_crate_name: tcx.crate_name(LOCAL_CRATE),
|
||||
decl_crate_name: tcx.crate_name(decl_crate),
|
||||
name: tcx.item_name(decl_did),
|
||||
span: decl.span,
|
||||
help: (),
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// if it's not local, who cares about generating it.
|
||||
// That's the local crates' responsibility
|
||||
let Some(chosen_impl) = local_impl.as_local() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
tracing::debug!("generating EII {chosen_impl:?} (default={is_default})");
|
||||
}
|
||||
}
|
||||
|
|
@ -1344,3 +1344,41 @@ pub(crate) struct EiiWithTrackCaller {
|
|||
#[label]
|
||||
pub sig_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_eii_without_impl)]
|
||||
pub(crate) struct EiiWithoutImpl {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
|
||||
pub current_crate_name: Symbol,
|
||||
pub decl_crate_name: Symbol,
|
||||
#[help]
|
||||
pub help: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_duplicate_eii_impls)]
|
||||
pub(crate) struct DuplicateEiiImpls {
|
||||
pub name: Symbol,
|
||||
|
||||
#[primary_span]
|
||||
#[label(passes_first)]
|
||||
pub first_span: Span,
|
||||
pub first_crate: Symbol,
|
||||
|
||||
#[label(passes_second)]
|
||||
pub second_span: Span,
|
||||
pub second_crate: Symbol,
|
||||
|
||||
#[note]
|
||||
pub additional_crates: Option<()>,
|
||||
|
||||
pub num_additional_crates: usize,
|
||||
pub additional_crate_names: String,
|
||||
|
||||
#[help]
|
||||
pub help: (),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ mod check_export;
|
|||
pub mod dead;
|
||||
mod debugger_visualizer;
|
||||
mod diagnostic_items;
|
||||
mod eii;
|
||||
pub mod entry;
|
||||
mod errors;
|
||||
pub mod hir_id_validator;
|
||||
|
|
@ -43,4 +44,5 @@ pub fn provide(providers: &mut Providers) {
|
|||
stability::provide(providers);
|
||||
upvars::provide(providers);
|
||||
check_export::provide(providers);
|
||||
providers.check_externally_implementable_items = eii::check_externally_implementable_items;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue