1//! Checks necessary for externally implementable items:
2//! Are all items implemented etc.?
34use std::iter;
56use rustc_data_structures::fx::FxIndexMap;
7use rustc_hir::attrs::{EiiDecl, EiiImpl};
8use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
9use rustc_middle::ty::TyCtxt;
10use rustc_session::config::CrateType;
1112use crate::errors::{DuplicateEiiImpls, EiiWithoutImpl};
1314#[derive(#[automatically_derived]
impl ::core::clone::Clone for CheckingMode {
#[inline]
fn clone(&self) -> CheckingMode { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CheckingMode { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for CheckingMode {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
CheckingMode::CheckDuplicates => "CheckDuplicates",
CheckingMode::CheckExistence => "CheckExistence",
})
}
}Debug)]
15enum CheckingMode {
16 CheckDuplicates,
17 CheckExistence,
18}
1920fn get_checking_mode(tcx: TyCtxt<'_>) -> CheckingMode {
21// if any of the crate types is not rlib or dylib, we must check for existence.
22if tcx.crate_types().iter().any(|i| !#[allow(non_exhaustive_omitted_patterns)] match i {
CrateType::Rlib | CrateType::Dylib => true,
_ => false,
}matches!(i, CrateType::Rlib | CrateType::Dylib)) {
23 CheckingMode::CheckExistence24 } else {
25 CheckingMode::CheckDuplicates26 }
27}
2829/// Checks for a given crate, what EIIs need to be generated in it.
30/// This is usually a small subset of all EIIs.
31///
32/// EII implementations come in two varieties: explicit and default.
33/// This query is called once for every crate, to check whether there aren't any duplicate explicit implementations.
34/// A duplicate may be caused by an implementation in the current crate,
35/// though it's also entirely possible that the source is two dependencies with an explicit implementation.
36/// Those work fine on their own but the combination of the two is a conflict.
37///
38/// However, if the current crate is a "root" crate, one that generates a final artifact like a binary,
39/// then we check one more thing, namely that every EII actually has an implementation, either default or not.
40/// If one EII has no implementation, that's an error at that point.
41///
42/// These two behaviors are implemented using `CheckingMode`.
43pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) {
44let checking_mode = get_checking_mode(tcx);
4546#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FoundImpl {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "FoundImpl",
"imp", &self.imp, "impl_crate", &&self.impl_crate)
}
}Debug)]
47struct FoundImpl {
48 imp: EiiImpl,
49 impl_crate: CrateNum,
50 }
5152#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FoundEii {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "FoundEii",
"decl", &self.decl, "decl_crate", &self.decl_crate, "impls",
&&self.impls)
}
}Debug)]
53struct FoundEii {
54 decl: EiiDecl,
55 decl_crate: CrateNum,
56 impls: FxIndexMap<DefId, FoundImpl>,
57 }
5859let mut eiis = FxIndexMap::<DefId, FoundEii>::default();
6061// collect all the EII declarations, and possibly implementations from all descendent crates
62for &cnum in tcx.crates(()).iter().chain(iter::once(&LOCAL_CRATE)) {
63// get the eiis for the crate we're currently looking at
64let crate_eiis = tcx.externally_implementable_items(cnum);
6566// update or insert the corresponding entries
67for (did, (decl, impls)) in crate_eiis {
68 eiis.entry(*did)
69 .or_insert_with(|| FoundEii {
70 decl: *decl,
71 decl_crate: cnum,
72 impls: Default::default(),
73 })
74 .impls
75 .extend(
76 impls
77 .into_iter()
78 .map(|(did, i)| (*did, FoundImpl { imp: *i, impl_crate: cnum })),
79 );
80 }
81 }
8283// now we have all eiis! For each of them, choose one we want to actually generate.
84for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis {
85let mut default_impls = Vec::new();
86let mut explicit_impls = Vec::new();
8788for (impl_did, FoundImpl { imp, impl_crate }) in impls {
89if imp.is_default {
90 default_impls.push((impl_did, impl_crate));
91 } else {
92 explicit_impls.push((impl_did, impl_crate));
93 }
94 }
9596// more than one explicit implementation (across all crates)
97 // is instantly an error.
98if explicit_impls.len() > 1 {
99 tcx.dcx().emit_err(DuplicateEiiImpls {
100 name: decl.name.name,
101 first_span: tcx.def_span(explicit_impls[0].0),
102 first_crate: tcx.crate_name(explicit_impls[0].1),
103 second_span: tcx.def_span(explicit_impls[1].0),
104 second_crate: tcx.crate_name(explicit_impls[1].1),
105106 help: (),
107108 additional_crates: (explicit_impls.len() > 2).then_some(()),
109 num_additional_crates: explicit_impls.len() - 2,
110 additional_crate_names: explicit_impls[2..]
111 .iter()
112 .map(|i| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", tcx.crate_name(i.1)))
})format!("`{}`", tcx.crate_name(i.1)))
113 .collect::<Vec<_>>()
114 .join(", "),
115 });
116 }
117118if default_impls.len() > 1 {
119let decl_span = tcx.def_ident_span(foreign_item).unwrap();
120 tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now");
121 }
122123let (local_impl, is_default) =
124// note, for a single crate we never need to generate both a default and an explicit implementation.
125 // In that case, generating the explicit implementation is enough!
126match (checking_mode, explicit_impls.first(), default_impls.first()) {
127// If we find an explicit implementation, it's instantly the chosen implementation.
128(_, Some((explicit, _)), _) => (explicit, false),
129// if we find a default implementation, we can emit it but the alias should be weak
130(_, _, Some((deflt, _))) => (deflt, true),
131132// if we find no explicit implementation,
133 // that's fine if we're only checking for duplicates.
134 // The existence will be checked somewhere else in a crate downstream.
135(CheckingMode::CheckDuplicates, None, _) => continue,
136137// We have a target to generate, but no impl to put in it. error!
138(CheckingMode::CheckExistence, None, None) => {
139 tcx.dcx().emit_err(EiiWithoutImpl {
140 current_crate_name: tcx.crate_name(LOCAL_CRATE),
141 decl_crate_name: tcx.crate_name(decl_crate),
142// FIXME: shouldn't call `item_name`
143name: decl.name.name,
144 span: decl.name.span,
145 help: (),
146 });
147148continue;
149 }
150 };
151152// if it's not local, who cares about generating it.
153 // That's the local crates' responsibility
154let Some(chosen_impl) = local_impl.as_local() else {
155continue;
156 };
157158{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_passes/src/eii.rs:158",
"rustc_passes::eii", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_passes/src/eii.rs"),
::tracing_core::__macro_support::Option::Some(158u32),
::tracing_core::__macro_support::Option::Some("rustc_passes::eii"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("generating EII {0:?} (default={1})",
chosen_impl, is_default) as &dyn Value))])
});
} else { ; }
};tracing::debug!("generating EII {chosen_impl:?} (default={is_default})");
159 }
160}