]> git.lizzy.rs Git - rust.git/blob - src/librustc_passes/lang_items.rs
Rollup merge of #71263 - shlevy:FileLoader-remove-abs_path, r=Xanewok
[rust.git] / src / librustc_passes / lang_items.rs
1 //! Detecting language items.
2 //!
3 //! Language items are items that represent concepts intrinsic to the language
4 //! itself. Examples are:
5 //!
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.
9
10 use crate::weak_lang_items;
11
12 use rustc_middle::middle::cstore::ExternCrate;
13 use rustc_middle::ty::TyCtxt;
14
15 use rustc_errors::struct_span_err;
16 use rustc_hir as hir;
17 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
18 use rustc_hir::itemlikevisit::ItemLikeVisitor;
19 use rustc_hir::lang_items::{extract, ITEM_REFS};
20 use rustc_hir::{LangItem, LanguageItems, Target};
21
22 use rustc_middle::ty::query::Providers;
23
24 struct LanguageItemCollector<'tcx> {
25     items: LanguageItems,
26     tcx: TyCtxt<'tcx>,
27 }
28
29 impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
30     fn visit_item(&mut self, item: &hir::Item<'_>) {
31         if let Some((value, span)) = extract(&item.attrs) {
32             let actual_target = Target::from_item(item);
33             match ITEM_REFS.get(&*value.as_str()).cloned() {
34                 // Known lang item with attribute on correct target.
35                 Some((item_index, expected_target)) if actual_target == expected_target => {
36                     let def_id = self.tcx.hir().local_def_id(item.hir_id);
37                     self.collect_item(item_index, def_id.to_def_id());
38                 }
39                 // Known lang item with attribute on incorrect target.
40                 Some((_, expected_target)) => {
41                     struct_span_err!(
42                         self.tcx.sess,
43                         span,
44                         E0718,
45                         "`{}` language item must be applied to a {}",
46                         value,
47                         expected_target,
48                     )
49                     .span_label(
50                         span,
51                         format!(
52                             "attribute should be applied to a {}, not a {}",
53                             expected_target, actual_target,
54                         ),
55                     )
56                     .emit();
57                 }
58                 // Unknown lang item.
59                 _ => {
60                     struct_span_err!(
61                         self.tcx.sess,
62                         span,
63                         E0522,
64                         "definition of an unknown language item: `{}`",
65                         value
66                     )
67                     .span_label(span, format!("definition of unknown language item `{}`", value))
68                     .emit();
69                 }
70             }
71         }
72     }
73
74     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {
75         // At present, lang items are always items, not trait items.
76     }
77
78     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
79         // At present, lang items are always items, not impl items.
80     }
81 }
82
83 impl LanguageItemCollector<'tcx> {
84     fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
85         LanguageItemCollector { tcx, items: LanguageItems::new() }
86     }
87
88     fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
89         // Check for duplicates.
90         if let Some(original_def_id) = self.items.items[item_index] {
91             if original_def_id != item_def_id {
92                 let name = LangItem::from_u32(item_index as u32).unwrap().name();
93                 let mut err = match self.tcx.hir().span_if_local(item_def_id) {
94                     Some(span) => struct_span_err!(
95                         self.tcx.sess,
96                         span,
97                         E0152,
98                         "found duplicate lang item `{}`",
99                         name
100                     ),
101                     None => match self.tcx.extern_crate(item_def_id) {
102                         Some(ExternCrate { dependency_of, .. }) => {
103                             self.tcx.sess.struct_err(&format!(
104                                 "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
105                                 self.tcx.crate_name(item_def_id.krate),
106                                 self.tcx.crate_name(*dependency_of),
107                                 name
108                             ))
109                         }
110                         _ => self.tcx.sess.struct_err(&format!(
111                             "duplicate lang item in crate `{}`: `{}`.",
112                             self.tcx.crate_name(item_def_id.krate),
113                             name
114                         )),
115                     },
116                 };
117                 if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
118                     err.span_note(span, "the lang item is first defined here");
119                 } else {
120                     match self.tcx.extern_crate(original_def_id) {
121                         Some(ExternCrate { dependency_of, .. }) => {
122                             err.note(&format!(
123                                 "the lang item is first defined in crate `{}` (which `{}` depends on)",
124                                 self.tcx.crate_name(original_def_id.krate),
125                                 self.tcx.crate_name(*dependency_of)
126                             ));
127                         }
128                         _ => {
129                             err.note(&format!(
130                                 "the lang item is first defined in crate `{}`.",
131                                 self.tcx.crate_name(original_def_id.krate)
132                             ));
133                         }
134                     }
135                 }
136                 err.emit();
137             }
138         }
139
140         // Matched.
141         self.items.items[item_index] = Some(item_def_id);
142     }
143 }
144
145 /// Traverses and collects all the lang items in all crates.
146 fn collect(tcx: TyCtxt<'_>) -> LanguageItems {
147     // Initialize the collector.
148     let mut collector = LanguageItemCollector::new(tcx);
149
150     // Collect lang items in other crates.
151     for &cnum in tcx.crates().iter() {
152         for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() {
153             collector.collect_item(item_index, def_id);
154         }
155     }
156
157     // Collect lang items in this crate.
158     tcx.hir().krate().visit_all_item_likes(&mut collector);
159
160     // Extract out the found lang items.
161     let LanguageItemCollector { mut items, .. } = collector;
162
163     // Find all required but not-yet-defined lang items.
164     weak_lang_items::check_crate(tcx, &mut items);
165
166     items
167 }
168
169 pub fn provide(providers: &mut Providers<'_>) {
170     providers.get_lang_items = |tcx, id| {
171         assert_eq!(id, LOCAL_CRATE);
172         tcx.arena.alloc(collect(tcx))
173     };
174 }