|
9 | 9 |
|
10 | 10 | pub use self::LangItem::*; |
11 | 11 |
|
12 | | -use crate::middle::cstore::ExternCrate; |
13 | | -use crate::middle::weak_lang_items; |
14 | 12 | use crate::ty::{self, TyCtxt}; |
15 | 13 |
|
16 | | -use rustc_errors::struct_span_err; |
17 | | -use rustc_hir as hir; |
18 | 14 | use rustc_hir::def_id::DefId; |
19 | | -use rustc_hir::itemlikevisit::ItemLikeVisitor; |
20 | | -use rustc_lang_items::lang_items::ITEM_REFS; |
21 | | -use rustc_lang_items::Target; |
22 | | -use rustc_span::symbol::{sym, Symbol}; |
23 | 15 | use rustc_span::Span; |
24 | | -use syntax::ast; |
25 | 16 |
|
26 | 17 | pub use rustc_lang_items::{LangItem, LanguageItems}; |
27 | 18 |
|
28 | | -struct LanguageItemCollector<'tcx> { |
29 | | - items: LanguageItems, |
30 | | - tcx: TyCtxt<'tcx>, |
31 | | -} |
32 | | - |
33 | | -impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { |
34 | | - fn visit_item(&mut self, item: &hir::Item<'_>) { |
35 | | - if let Some((value, span)) = extract(&item.attrs) { |
36 | | - let actual_target = Target::from_item(item); |
37 | | - match ITEM_REFS.get(&*value.as_str()).cloned() { |
38 | | - // Known lang item with attribute on correct target. |
39 | | - Some((item_index, expected_target)) if actual_target == expected_target => { |
40 | | - let def_id = self.tcx.hir().local_def_id(item.hir_id); |
41 | | - self.collect_item(item_index, def_id); |
42 | | - } |
43 | | - // Known lang item with attribute on incorrect target. |
44 | | - Some((_, expected_target)) => { |
45 | | - struct_span_err!( |
46 | | - self.tcx.sess, |
47 | | - span, |
48 | | - E0718, |
49 | | - "`{}` language item must be applied to a {}", |
50 | | - value, |
51 | | - expected_target, |
52 | | - ) |
53 | | - .span_label( |
54 | | - span, |
55 | | - format!( |
56 | | - "attribute should be applied to a {}, not a {}", |
57 | | - expected_target, actual_target, |
58 | | - ), |
59 | | - ) |
60 | | - .emit(); |
61 | | - } |
62 | | - // Unknown lang item. |
63 | | - _ => { |
64 | | - struct_span_err!( |
65 | | - self.tcx.sess, |
66 | | - span, |
67 | | - E0522, |
68 | | - "definition of an unknown language item: `{}`", |
69 | | - value |
70 | | - ) |
71 | | - .span_label(span, format!("definition of unknown language item `{}`", value)) |
72 | | - .emit(); |
73 | | - } |
74 | | - } |
75 | | - } |
76 | | - } |
77 | | - |
78 | | - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) { |
79 | | - // At present, lang items are always items, not trait items. |
80 | | - } |
81 | | - |
82 | | - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) { |
83 | | - // At present, lang items are always items, not impl items. |
84 | | - } |
85 | | -} |
86 | | - |
87 | | -impl LanguageItemCollector<'tcx> { |
88 | | - fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { |
89 | | - LanguageItemCollector { tcx, items: LanguageItems::new() } |
90 | | - } |
91 | | - |
92 | | - fn collect_item(&mut self, item_index: usize, item_def_id: DefId) { |
93 | | - // Check for duplicates. |
94 | | - if let Some(original_def_id) = self.items.items[item_index] { |
95 | | - if original_def_id != item_def_id { |
96 | | - let name = LangItem::from_u32(item_index as u32).unwrap().name(); |
97 | | - let mut err = match self.tcx.hir().span_if_local(item_def_id) { |
98 | | - Some(span) => struct_span_err!( |
99 | | - self.tcx.sess, |
100 | | - span, |
101 | | - E0152, |
102 | | - "found duplicate lang item `{}`", |
103 | | - name |
104 | | - ), |
105 | | - None => match self.tcx.extern_crate(item_def_id) { |
106 | | - Some(ExternCrate { dependency_of, .. }) => { |
107 | | - self.tcx.sess.struct_err(&format!( |
108 | | - "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.", |
109 | | - self.tcx.crate_name(item_def_id.krate), |
110 | | - self.tcx.crate_name(*dependency_of), |
111 | | - name |
112 | | - )) |
113 | | - } |
114 | | - _ => self.tcx.sess.struct_err(&format!( |
115 | | - "duplicate lang item in crate `{}`: `{}`.", |
116 | | - self.tcx.crate_name(item_def_id.krate), |
117 | | - name |
118 | | - )), |
119 | | - }, |
120 | | - }; |
121 | | - if let Some(span) = self.tcx.hir().span_if_local(original_def_id) { |
122 | | - err.span_note(span, "the lang item is first defined here"); |
123 | | - } else { |
124 | | - match self.tcx.extern_crate(original_def_id) { |
125 | | - Some(ExternCrate { dependency_of, .. }) => { |
126 | | - err.note(&format!( |
127 | | - "the lang item is first defined in crate `{}` (which `{}` depends on)", |
128 | | - self.tcx.crate_name(original_def_id.krate), |
129 | | - self.tcx.crate_name(*dependency_of))); |
130 | | - } |
131 | | - _ => { |
132 | | - err.note(&format!( |
133 | | - "the lang item is first defined in crate `{}`.", |
134 | | - self.tcx.crate_name(original_def_id.krate) |
135 | | - )); |
136 | | - } |
137 | | - } |
138 | | - } |
139 | | - err.emit(); |
140 | | - } |
141 | | - } |
142 | | - |
143 | | - // Matched. |
144 | | - self.items.items[item_index] = Some(item_def_id); |
145 | | - } |
146 | | -} |
147 | | - |
148 | | -/// Extracts the first `lang = "$name"` out of a list of attributes. |
149 | | -/// The attributes `#[panic_handler]` and `#[alloc_error_handler]` |
150 | | -/// are also extracted out when found. |
151 | | -pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { |
152 | | - attrs.iter().find_map(|attr| { |
153 | | - Some(match attr { |
154 | | - _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span), |
155 | | - _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span), |
156 | | - _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span), |
157 | | - _ => return None, |
158 | | - }) |
159 | | - }) |
160 | | -} |
161 | | - |
162 | | -/// Traverses and collects all the lang items in all crates. |
163 | | -pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LanguageItems { |
164 | | - // Initialize the collector. |
165 | | - let mut collector = LanguageItemCollector::new(tcx); |
166 | | - |
167 | | - // Collect lang items in other crates. |
168 | | - for &cnum in tcx.crates().iter() { |
169 | | - for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() { |
170 | | - collector.collect_item(item_index, def_id); |
171 | | - } |
172 | | - } |
173 | | - |
174 | | - // Collect lang items in this crate. |
175 | | - tcx.hir().krate().visit_all_item_likes(&mut collector); |
176 | | - |
177 | | - // Extract out the found lang items. |
178 | | - let LanguageItemCollector { mut items, .. } = collector; |
179 | | - |
180 | | - // Find all required but not-yet-defined lang items. |
181 | | - weak_lang_items::check_crate(tcx, &mut items); |
182 | | - |
183 | | - items |
184 | | -} |
185 | | - |
186 | 19 | impl<'tcx> TyCtxt<'tcx> { |
187 | 20 | /// Returns the `DefId` for a given `LangItem`. |
188 | 21 | /// If not found, fatally aborts compilation. |
|
0 commit comments