]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
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 | ||
f035d41b | 10 | use crate::check_attr::target_from_impl_item; |
74b04a01 XL |
11 | use crate::weak_lang_items; |
12 | ||
ba9703b0 XL |
13 | use rustc_middle::middle::cstore::ExternCrate; |
14 | use rustc_middle::ty::TyCtxt; | |
74b04a01 XL |
15 | |
16 | use rustc_errors::struct_span_err; | |
17 | use rustc_hir as hir; | |
18 | use rustc_hir::def_id::{DefId, LOCAL_CRATE}; | |
19 | use rustc_hir::itemlikevisit::ItemLikeVisitor; | |
20 | use rustc_hir::lang_items::{extract, ITEM_REFS}; | |
f035d41b | 21 | use rustc_hir::{HirId, LangItem, LanguageItems, Target}; |
74b04a01 | 22 | |
ba9703b0 | 23 | use rustc_middle::ty::query::Providers; |
74b04a01 XL |
24 | |
25 | struct LanguageItemCollector<'tcx> { | |
26 | items: LanguageItems, | |
27 | tcx: TyCtxt<'tcx>, | |
28 | } | |
29 | ||
30 | impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { | |
31 | fn visit_item(&mut self, item: &hir::Item<'_>) { | |
6a06907d | 32 | self.check_for_lang(Target::from_item(item), item.hir_id()); |
3dfed10e XL |
33 | |
34 | if let hir::ItemKind::Enum(def, ..) = &item.kind { | |
35 | for variant in def.variants { | |
6a06907d | 36 | self.check_for_lang(Target::Variant, variant.id); |
3dfed10e XL |
37 | } |
38 | } | |
f035d41b XL |
39 | } |
40 | ||
41 | fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { | |
6a06907d | 42 | self.check_for_lang(Target::from_trait_item(trait_item), trait_item.hir_id()) |
f035d41b XL |
43 | } |
44 | ||
45 | fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { | |
6a06907d | 46 | self.check_for_lang(target_from_impl_item(self.tcx, impl_item), impl_item.hir_id()) |
f035d41b | 47 | } |
fc512014 XL |
48 | |
49 | fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {} | |
f035d41b XL |
50 | } |
51 | ||
52 | impl LanguageItemCollector<'tcx> { | |
53 | fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { | |
54 | LanguageItemCollector { tcx, items: LanguageItems::new() } | |
55 | } | |
56 | ||
6a06907d XL |
57 | fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { |
58 | let attrs = self.tcx.hir().attrs(hir_id); | |
3dfed10e XL |
59 | let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym); |
60 | if let Some((value, span)) = extract(check_name, &attrs) { | |
61 | match ITEM_REFS.get(&value).cloned() { | |
74b04a01 XL |
62 | // Known lang item with attribute on correct target. |
63 | Some((item_index, expected_target)) if actual_target == expected_target => { | |
f035d41b | 64 | let def_id = self.tcx.hir().local_def_id(hir_id); |
f9f354fc | 65 | self.collect_item(item_index, def_id.to_def_id()); |
74b04a01 XL |
66 | } |
67 | // Known lang item with attribute on incorrect target. | |
68 | Some((_, expected_target)) => { | |
69 | struct_span_err!( | |
70 | self.tcx.sess, | |
71 | span, | |
72 | E0718, | |
73 | "`{}` language item must be applied to a {}", | |
74 | value, | |
75 | expected_target, | |
76 | ) | |
77 | .span_label( | |
78 | span, | |
79 | format!( | |
80 | "attribute should be applied to a {}, not a {}", | |
81 | expected_target, actual_target, | |
82 | ), | |
83 | ) | |
84 | .emit(); | |
85 | } | |
86 | // Unknown lang item. | |
87 | _ => { | |
88 | struct_span_err!( | |
89 | self.tcx.sess, | |
90 | span, | |
91 | E0522, | |
92 | "definition of an unknown language item: `{}`", | |
93 | value | |
94 | ) | |
95 | .span_label(span, format!("definition of unknown language item `{}`", value)) | |
96 | .emit(); | |
97 | } | |
98 | } | |
99 | } | |
100 | } | |
101 | ||
74b04a01 XL |
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 { | |
f035d41b XL |
106 | let lang_item = LangItem::from_u32(item_index as u32).unwrap(); |
107 | let name = lang_item.name(); | |
74b04a01 XL |
108 | let mut err = match self.tcx.hir().span_if_local(item_def_id) { |
109 | Some(span) => struct_span_err!( | |
110 | self.tcx.sess, | |
111 | span, | |
112 | E0152, | |
113 | "found duplicate lang item `{}`", | |
114 | name | |
115 | ), | |
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), | |
122 | name | |
123 | )) | |
124 | } | |
125 | _ => self.tcx.sess.struct_err(&format!( | |
126 | "duplicate lang item in crate `{}`: `{}`.", | |
127 | self.tcx.crate_name(item_def_id.krate), | |
128 | name | |
129 | )), | |
130 | }, | |
131 | }; | |
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"); | |
134 | } else { | |
135 | match self.tcx.extern_crate(original_def_id) { | |
136 | Some(ExternCrate { dependency_of, .. }) => { | |
137 | err.note(&format!( | |
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) | |
141 | )); | |
142 | } | |
143 | _ => { | |
144 | err.note(&format!( | |
145 | "the lang item is first defined in crate `{}`.", | |
146 | self.tcx.crate_name(original_def_id.krate) | |
147 | )); | |
148 | } | |
149 | } | |
f035d41b XL |
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) | |
154 | } else { | |
155 | let paths: Vec<_> = self | |
156 | .tcx | |
157 | .crate_extern_paths(def_id.krate) | |
158 | .iter() | |
159 | .map(|p| p.display().to_string()) | |
160 | .collect(); | |
161 | format!( | |
162 | "{} definition in `{}` loaded from {}", | |
163 | which, | |
164 | crate_name, | |
165 | paths.join(", ") | |
166 | ) | |
167 | }; | |
168 | err.note(¬e); | |
169 | }; | |
170 | note_def("first", original_def_id); | |
171 | note_def("second", item_def_id); | |
74b04a01 XL |
172 | } |
173 | err.emit(); | |
174 | } | |
175 | } | |
176 | ||
177 | // Matched. | |
178 | self.items.items[item_index] = Some(item_def_id); | |
f035d41b XL |
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); | |
181 | } | |
74b04a01 XL |
182 | } |
183 | } | |
184 | ||
185 | /// Traverses and collects all the lang items in all crates. | |
ba9703b0 | 186 | fn collect(tcx: TyCtxt<'_>) -> LanguageItems { |
74b04a01 XL |
187 | // Initialize the collector. |
188 | let mut collector = LanguageItemCollector::new(tcx); | |
189 | ||
190 | // Collect lang items in other crates. | |
191 | for &cnum in tcx.crates().iter() { | |
192 | for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() { | |
193 | collector.collect_item(item_index, def_id); | |
194 | } | |
195 | } | |
196 | ||
197 | // Collect lang items in this crate. | |
198 | tcx.hir().krate().visit_all_item_likes(&mut collector); | |
199 | ||
200 | // Extract out the found lang items. | |
201 | let LanguageItemCollector { mut items, .. } = collector; | |
202 | ||
203 | // Find all required but not-yet-defined lang items. | |
204 | weak_lang_items::check_crate(tcx, &mut items); | |
205 | ||
206 | items | |
207 | } | |
208 | ||
f035d41b | 209 | pub fn provide(providers: &mut Providers) { |
74b04a01 XL |
210 | providers.get_lang_items = |tcx, id| { |
211 | assert_eq!(id, LOCAL_CRATE); | |
f9f354fc | 212 | collect(tcx) |
74b04a01 XL |
213 | }; |
214 | } |