1 //! Detecting language items.
3 //! Language items are items that represent concepts intrinsic to the language
4 //! itself. Examples are:
6 //! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
7 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
8 //! * Functions called by the compiler itself.
10 use crate::check_attr
::target_from_impl_item
;
12 DuplicateLangItem
, IncorrectTarget
, LangItemOnIncorrectTarget
, UnknownLangItem
,
14 use crate::weak_lang_items
;
17 use rustc_hir
::def
::DefKind
;
18 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
19 use rustc_hir
::lang_items
::{extract, GenericRequirement}
;
20 use rustc_hir
::{LangItem, LanguageItems, Target}
;
21 use rustc_middle
::ty
::TyCtxt
;
22 use rustc_session
::cstore
::ExternCrate
;
23 use rustc_span
::symbol
::kw
::Empty
;
24 use rustc_span
::{sym, Span}
;
26 use rustc_middle
::query
::Providers
;
28 pub(crate) enum Duplicate
{
34 struct LanguageItemCollector
<'tcx
> {
39 impl<'tcx
> LanguageItemCollector
<'tcx
> {
40 fn new(tcx
: TyCtxt
<'tcx
>) -> LanguageItemCollector
<'tcx
> {
41 LanguageItemCollector { tcx, items: LanguageItems::new() }
44 fn check_for_lang(&mut self, actual_target
: Target
, def_id
: LocalDefId
) {
45 let attrs
= self.tcx
.hir().attrs(self.tcx
.hir().local_def_id_to_hir_id(def_id
));
46 if let Some((name
, span
)) = extract(&attrs
) {
47 match LangItem
::from_name(name
) {
48 // Known lang item with attribute on correct target.
49 Some(lang_item
) if actual_target
== lang_item
.target() => {
50 self.collect_item_extended(lang_item
, def_id
, span
);
52 // Known lang item with attribute on incorrect target.
54 self.tcx
.sess
.emit_err(LangItemOnIncorrectTarget
{
57 expected_target
: lang_item
.target(),
63 self.tcx
.sess
.emit_err(UnknownLangItem { span, name }
);
69 fn collect_item(&mut self, lang_item
: LangItem
, item_def_id
: DefId
) {
70 // Check for duplicates.
71 if let Some(original_def_id
) = self.items
.get(lang_item
) {
72 if original_def_id
!= item_def_id
{
73 let local_span
= self.tcx
.hir().span_if_local(item_def_id
);
74 let lang_item_name
= lang_item
.name();
75 let crate_name
= self.tcx
.crate_name(item_def_id
.krate
);
76 let mut dependency_of
= Empty
;
77 let is_local
= item_def_id
.is_local();
78 let path
= if is_local
{
82 .crate_extern_paths(item_def_id
.krate
)
84 .map(|p
| p
.display().to_string())
88 let first_defined_span
= self.tcx
.hir().span_if_local(original_def_id
);
89 let mut orig_crate_name
= Empty
;
90 let mut orig_dependency_of
= Empty
;
91 let orig_is_local
= original_def_id
.is_local();
92 let orig_path
= if orig_is_local
{
96 .crate_extern_paths(original_def_id
.krate
)
98 .map(|p
| p
.display().to_string())
102 if first_defined_span
.is_none() {
103 orig_crate_name
= self.tcx
.crate_name(original_def_id
.krate
);
104 if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }
) =
105 self.tcx
.extern_crate(original_def_id
)
107 orig_dependency_of
= self.tcx
.crate_name(*inner_dependency_of
);
111 let duplicate
= if local_span
.is_some() {
114 match self.tcx
.extern_crate(item_def_id
) {
115 Some(ExternCrate { dependency_of: inner_dependency_of, .. }
) => {
116 dependency_of
= self.tcx
.crate_name(*inner_dependency_of
);
117 Duplicate
::CrateDepends
119 _
=> Duplicate
::Crate
,
123 self.tcx
.sess
.emit_err(DuplicateLangItem
{
141 self.items
.set(lang_item
, item_def_id
);
144 // Like collect_item() above, but also checks whether the lang item is declared
145 // with the right number of generic arguments.
146 fn collect_item_extended(&mut self, lang_item
: LangItem
, item_def_id
: LocalDefId
, span
: Span
) {
147 let name
= lang_item
.name();
149 // Now check whether the lang_item has the expected number of generic
150 // arguments. Generally speaking, binary and indexing operations have
151 // one (for the RHS/index), unary operations have none, the closure
152 // traits have one for the argument list, generators have one for the
153 // resume argument, and ordering/equality relations have one for the RHS
154 // Some other types like Box and various functions like drop_in_place
155 // have minimum requirements.
157 if let hir
::Node
::Item(hir
::Item { kind, span: item_span, .. }
) =
158 self.tcx
.hir().get_by_def_id(item_def_id
)
160 let (actual_num
, generics_span
) = match kind
.generics() {
165 .filter(|p
| !self.tcx
.has_attr(p
.def_id
, sym
::rustc_host
))
169 None
=> (0, *item_span
),
172 let mut at_least
= false;
173 let required
= match lang_item
.required_generics() {
174 GenericRequirement
::Exact(num
) if num
!= actual_num
=> Some(num
),
175 GenericRequirement
::Minimum(num
) if actual_num
< num
=> {
179 // If the number matches, or there is no requirement, handle it normally
183 if let Some(num
) = required
{
184 // We are issuing E0718 "incorrect target" here, because while the
185 // item kind of the target is correct, the target is still wrong
186 // because of the wrong number of generic arguments.
187 self.tcx
.sess
.emit_err(IncorrectTarget
{
197 // return early to not collect the lang item
202 self.collect_item(lang_item
, item_def_id
.to_def_id());
206 /// Traverses and collects all the lang items in all crates.
207 fn get_lang_items(tcx
: TyCtxt
<'_
>, (): ()) -> LanguageItems
{
208 // Initialize the collector.
209 let mut collector
= LanguageItemCollector
::new(tcx
);
211 // Collect lang items in other crates.
212 for &cnum
in tcx
.crates(()).iter() {
213 for &(def_id
, lang_item
) in tcx
.defined_lang_items(cnum
).iter() {
214 collector
.collect_item(lang_item
, def_id
);
218 // Collect lang items in this crate.
219 let crate_items
= tcx
.hir_crate_items(());
221 for id
in crate_items
.items() {
223 .check_for_lang(Target
::from_def_kind(tcx
.def_kind(id
.owner_id
)), id
.owner_id
.def_id
);
225 if matches
!(tcx
.def_kind(id
.owner_id
), DefKind
::Enum
) {
226 let item
= tcx
.hir().item(id
);
227 if let hir
::ItemKind
::Enum(def
, ..) = &item
.kind
{
228 for variant
in def
.variants
{
229 collector
.check_for_lang(Target
::Variant
, variant
.def_id
);
235 // FIXME: avoid calling trait_item() when possible
236 for id
in crate_items
.trait_items() {
237 let item
= tcx
.hir().trait_item(id
);
238 collector
.check_for_lang(Target
::from_trait_item(item
), item
.owner_id
.def_id
)
241 // FIXME: avoid calling impl_item() when possible
242 for id
in crate_items
.impl_items() {
243 let item
= tcx
.hir().impl_item(id
);
244 collector
.check_for_lang(target_from_impl_item(tcx
, item
), item
.owner_id
.def_id
)
247 // Extract out the found lang items.
248 let LanguageItemCollector { mut items, .. }
= collector
;
250 // Find all required but not-yet-defined lang items.
251 weak_lang_items
::check_crate(tcx
, &mut items
);
256 pub fn provide(providers
: &mut Providers
) {
257 providers
.get_lang_items
= get_lang_items
;