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
;
11 use crate::weak_lang_items
;
13 use rustc_middle
::middle
::cstore
::ExternCrate
;
14 use rustc_middle
::ty
::TyCtxt
;
16 use rustc_errors
::{pluralize, struct_span_err}
;
18 use rustc_hir
::def_id
::DefId
;
19 use rustc_hir
::itemlikevisit
::ItemLikeVisitor
;
20 use rustc_hir
::lang_items
::{extract, ITEM_REFS}
;
21 use rustc_hir
::{HirId, LangItem, LanguageItems, Target}
;
24 use rustc_middle
::ty
::query
::Providers
;
26 struct LanguageItemCollector
<'tcx
> {
31 impl ItemLikeVisitor
<'v
> for LanguageItemCollector
<'tcx
> {
32 fn visit_item(&mut self, item
: &hir
::Item
<'_
>) {
33 self.check_for_lang(Target
::from_item(item
), item
.hir_id());
35 if let hir
::ItemKind
::Enum(def
, ..) = &item
.kind
{
36 for variant
in def
.variants
{
37 self.check_for_lang(Target
::Variant
, variant
.id
);
42 fn visit_trait_item(&mut self, trait_item
: &hir
::TraitItem
<'_
>) {
43 self.check_for_lang(Target
::from_trait_item(trait_item
), trait_item
.hir_id())
46 fn visit_impl_item(&mut self, impl_item
: &hir
::ImplItem
<'_
>) {
47 self.check_for_lang(target_from_impl_item(self.tcx
, impl_item
), impl_item
.hir_id())
50 fn visit_foreign_item(&mut self, _
: &hir
::ForeignItem
<'_
>) {}
53 impl LanguageItemCollector
<'tcx
> {
54 fn new(tcx
: TyCtxt
<'tcx
>) -> LanguageItemCollector
<'tcx
> {
55 LanguageItemCollector { tcx, items: LanguageItems::new() }
58 fn check_for_lang(&mut self, actual_target
: Target
, hir_id
: HirId
) {
59 let attrs
= self.tcx
.hir().attrs(hir_id
);
60 let check_name
= |attr
, sym
| self.tcx
.sess
.check_name(attr
, sym
);
61 if let Some((value
, span
)) = extract(check_name
, &attrs
) {
62 match ITEM_REFS
.get(&value
).cloned() {
63 // Known lang item with attribute on correct target.
64 Some((item_index
, expected_target
)) if actual_target
== expected_target
=> {
65 self.collect_item_extended(item_index
, hir_id
, span
);
67 // Known lang item with attribute on incorrect target.
68 Some((_
, expected_target
)) => {
73 "`{}` language item must be applied to a {}",
80 "attribute should be applied to a {}, not a {}",
81 expected_target
, actual_target
,
92 "definition of an unknown language item: `{}`",
95 .span_label(span
, format
!("definition of unknown language item `{}`", value
))
102 fn collect_item(&mut self, item_index
: usize, item_def_id
: DefId
) {
103 // Check for duplicates.
104 if let Some(original_def_id
) = self.items
.items
[item_index
] {
105 if original_def_id
!= item_def_id
{
106 let lang_item
= LangItem
::from_u32(item_index
as u32).unwrap();
107 let name
= lang_item
.name();
108 let mut err
= match self.tcx
.hir().span_if_local(item_def_id
) {
109 Some(span
) => struct_span_err
!(
113 "found duplicate lang item `{}`",
116 None
=> match self.tcx
.extern_crate(item_def_id
) {
117 Some(ExternCrate { dependency_of, .. }
) => {
118 self.tcx
.sess
.struct_err(&format
!(
119 "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
120 self.tcx
.crate_name(item_def_id
.krate
),
121 self.tcx
.crate_name(*dependency_of
),
125 _
=> self.tcx
.sess
.struct_err(&format
!(
126 "duplicate lang item in crate `{}`: `{}`.",
127 self.tcx
.crate_name(item_def_id
.krate
),
132 if let Some(span
) = self.tcx
.hir().span_if_local(original_def_id
) {
133 err
.span_note(span
, "the lang item is first defined here");
135 match self.tcx
.extern_crate(original_def_id
) {
136 Some(ExternCrate { dependency_of, .. }
) => {
138 "the lang item is first defined in crate `{}` (which `{}` depends on)",
139 self.tcx
.crate_name(original_def_id
.krate
),
140 self.tcx
.crate_name(*dependency_of
)
145 "the lang item is first defined in crate `{}`.",
146 self.tcx
.crate_name(original_def_id
.krate
)
150 let mut note_def
= |which
, def_id
: DefId
| {
151 let crate_name
= self.tcx
.crate_name(def_id
.krate
);
152 let note
= if def_id
.is_local() {
153 format
!("{} definition in the local crate (`{}`)", which
, crate_name
)
155 let paths
: Vec
<_
> = self
157 .crate_extern_paths(def_id
.krate
)
159 .map(|p
| p
.display().to_string())
162 "{} definition in `{}` loaded from {}",
170 note_def("first", original_def_id
);
171 note_def("second", item_def_id
);
178 self.items
.items
[item_index
] = Some(item_def_id
);
179 if let Some(group
) = LangItem
::from_u32(item_index
as u32).unwrap().group() {
180 self.items
.groups
[group
as usize].push(item_def_id
);
184 // Like collect_item() above, but also checks whether the lang item is declared
185 // with the right number of generic arguments if it is a trait.
186 fn collect_item_extended(&mut self, item_index
: usize, hir_id
: HirId
, span
: Span
) {
187 let item_def_id
= self.tcx
.hir().local_def_id(hir_id
).to_def_id();
188 let lang_item
= LangItem
::from_u32(item_index
as u32).unwrap();
189 let name
= lang_item
.name();
191 self.collect_item(item_index
, item_def_id
);
193 // Now check whether the lang_item has the expected number of generic
194 // arguments if it is a trait. Generally speaking, binary and indexing
195 // operations have one (for the RHS/index), unary operations have none,
196 // and the rest also have none except for the closure traits (one for
197 // the argument list), generators (one for the resume argument),
198 // ordering/equality relations (one for the RHS), and various conversion
201 let expected_num
= match lang_item
{
213 | LangItem
::AddAssign
214 | LangItem
::SubAssign
215 | LangItem
::MulAssign
216 | LangItem
::DivAssign
217 | LangItem
::RemAssign
218 | LangItem
::BitXorAssign
219 | LangItem
::BitAndAssign
220 | LangItem
::BitOrAssign
221 | LangItem
::ShlAssign
222 | LangItem
::ShrAssign
228 | LangItem
::CoerceUnsized
229 | LangItem
::DispatchFromDyn
233 | LangItem
::Generator
234 | LangItem
::PartialEq
235 | LangItem
::PartialOrd
246 | LangItem
::StructuralPeq
247 | LangItem
::StructuralTeq
251 | LangItem
::DiscriminantKind
252 | LangItem
::PointeeTrait
258 | LangItem
::Termination
261 | LangItem
::UnwindSafe
262 | LangItem
::RefUnwindSafe
269 if let Some(expected_num
) = expected_num
{
270 let (actual_num
, generics_span
) = match self.tcx
.hir().get(hir_id
) {
271 hir
::Node
::Item(hir
::Item
{
272 kind
: hir
::ItemKind
::Trait(_
, _
, generics
, ..),
274 }) => (generics
.params
.len(), generics
.span
),
275 _
=> bug
!("op/index/deref lang item target is not a trait: {:?}", lang_item
),
278 if expected_num
!= actual_num
{
279 // We are issuing E0718 "incorrect target" here, because while the
280 // item kind of the target is correct, the target is still wrong
281 // because of the wrong number of generic arguments.
286 "`{}` language item must be applied to a trait with {} generic argument{}",
289 pluralize
!(expected_num
)
294 "this trait has {} generic argument{}, not {}",
296 pluralize
!(actual_num
),
306 /// Traverses and collects all the lang items in all crates.
307 fn get_lang_items(tcx
: TyCtxt
<'_
>, (): ()) -> LanguageItems
{
308 // Initialize the collector.
309 let mut collector
= LanguageItemCollector
::new(tcx
);
311 // Collect lang items in other crates.
312 for &cnum
in tcx
.crates().iter() {
313 for &(def_id
, item_index
) in tcx
.defined_lang_items(cnum
).iter() {
314 collector
.collect_item(item_index
, def_id
);
318 // Collect lang items in this crate.
319 tcx
.hir().krate().visit_all_item_likes(&mut collector
);
321 // Extract out the found lang items.
322 let LanguageItemCollector { mut items, .. }
= collector
;
324 // Find all required but not-yet-defined lang items.
325 weak_lang_items
::check_crate(tcx
, &mut items
);
330 pub fn provide(providers
: &mut Providers
) {
331 providers
.get_lang_items
= get_lang_items
;