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::error::DuplicateEiiImpls;
10use rustc_middle::ty::TyCtxt;
11use rustc_session::config::CrateType;
1213use crate::diagnostics::EiiWithoutImpl;
1415#[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)]
16enum CheckingMode {
17 CheckDuplicates,
18 CheckExistence,
19}
2021fn get_checking_mode(tcx: TyCtxt<'_>) -> CheckingMode {
22// if any of the crate types is not rlib, we must check for existence.
23if tcx.crate_types().iter().any(|i| !#[allow(non_exhaustive_omitted_patterns)] match i {
CrateType::Rlib => true,
_ => false,
}matches!(i, CrateType::Rlib)) {
24 CheckingMode::CheckExistence25 } else {
26 CheckingMode::CheckDuplicates27 }
28}
2930/// Checks for a given crate, what EIIs need to be generated in it.
31/// This is usually a small subset of all EIIs.
32///
33/// EII implementations come in two varieties: explicit and default.
34/// This query is called once for every crate, to check whether there aren't any duplicate explicit implementations.
35/// A duplicate may be caused by an implementation in the current crate,
36/// though it's also entirely possible that the source is two dependencies with an explicit implementation.
37/// Those work fine on their own but the combination of the two is a conflict.
38///
39/// However, if the current crate is a "root" crate, one that generates a final artifact like a binary,
40/// then we check one more thing, namely that every EII actually has an implementation, either default or not.
41/// If one EII has no implementation, that's an error at that point.
42///
43/// These two behaviors are implemented using `CheckingMode`.
44pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) {
45let checking_mode = get_checking_mode(tcx);
4647#[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)]
48struct FoundImpl {
49 imp: EiiImpl,
50 impl_crate: CrateNum,
51 }
5253#[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)]
54struct FoundEii {
55 decl: EiiDecl,
56 decl_crate: CrateNum,
57 impls: FxIndexMap<DefId, FoundImpl>,
58 }
5960let mut eiis = FxIndexMap::<DefId, FoundEii>::default();
6162// collect all the EII declarations, and possibly implementations from all descendent crates
63for &cnum in tcx.crates(()).iter().chain(iter::once(&LOCAL_CRATE)) {
64// get the eiis for the crate we're currently looking at
65let crate_eiis = tcx.externally_implementable_items(cnum);
6667// update or insert the corresponding entries
68for (did, (decl, impls)) in crate_eiis {
69 eiis.entry(*did)
70 .or_insert_with(|| FoundEii {
71 decl: *decl,
72 decl_crate: cnum,
73 impls: Default::default(),
74 })
75 .impls
76 .extend(
77 impls
78 .into_iter()
79 .map(|(did, i)| (*did, FoundImpl { imp: *i, impl_crate: cnum })),
80 );
81 }
82 }
8384// now we have all eiis! For each of them, choose one we want to actually generate.
85for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis {
86let mut default_impls = Vec::new();
87let mut explicit_impls = Vec::new();
8889for (impl_did, FoundImpl { imp, impl_crate }) in impls {
90if imp.is_default {
91 default_impls.push((impl_did, impl_crate));
92 } else {
93 explicit_impls.push((impl_did, impl_crate));
94 }
95 }
9697// more than one explicit implementation (across all crates)
98 // is instantly an error.
99if explicit_impls.len() > 1 {
100 tcx.dcx().emit_err(DuplicateEiiImpls {
101 name: decl.name.name,
102 first_span: tcx.def_span(explicit_impls[0].0),
103 first_crate: tcx.crate_name(explicit_impls[0].1),
104 second_span: tcx.def_span(explicit_impls[1].0),
105 second_crate: tcx.crate_name(explicit_impls[1].1),
106107 help: (),
108109 additional_crates: (explicit_impls.len() > 2).then_some(()),
110 num_additional_crates: explicit_impls.len() - 2,
111 additional_crate_names: explicit_impls[2..]
112 .iter()
113 .map(|i| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", tcx.crate_name(i.1)))
})format!("`{}`", tcx.crate_name(i.1)))
114 .collect::<Vec<_>>()
115 .join(", "),
116 });
117 }
118119if default_impls.len() > 1 {
120let decl_span = tcx.def_ident_span(foreign_item).unwrap();
121 tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now");
122 }
123124let (local_impl, is_default) =
125// note, for a single crate we never need to generate both a default and an explicit implementation.
126 // In that case, generating the explicit implementation is enough!
127match (checking_mode, explicit_impls.first(), default_impls.first()) {
128// If we find an explicit implementation, it's instantly the chosen implementation.
129(_, Some((explicit, _)), _) => (explicit, false),
130// if we find a default implementation, we can emit it but the alias should be weak
131(_, _, Some((deflt, _))) => (deflt, true),
132133// if we find no explicit implementation,
134 // that's fine if we're only checking for duplicates.
135 // The existence will be checked somewhere else in a crate downstream.
136(CheckingMode::CheckDuplicates, None, _) => continue,
137138// We have a target to generate, but no impl to put in it. error!
139(CheckingMode::CheckExistence, None, None) => {
140 tcx.dcx().emit_err(EiiWithoutImpl {
141 current_crate_name: tcx.crate_name(LOCAL_CRATE),
142 decl_crate_name: tcx.crate_name(decl_crate),
143// FIXME: shouldn't call `item_name`
144name: decl.name.name,
145 kind: tcx.def_kind(decl.foreign_item).descr(decl.foreign_item),
146 span: decl.name.span,
147 help: (),
148 });
149150continue;
151 }
152 };
153154// if it's not local, who cares about generating it.
155 // That's the local crates' responsibility
156let Some(chosen_impl) = local_impl.as_local() else {
157continue;
158 };
159160{
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:160",
"rustc_passes::eii", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_passes/src/eii.rs"),
::tracing_core::__macro_support::Option::Some(160u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("generating EII {0:?} (default={1})",
chosen_impl, is_default) as &dyn ::tracing::field::Value))])
});
} else { ; }
};tracing::debug!("generating EII {chosen_impl:?} (default={is_default})");
161 }
162}