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