1use rustc_ast as ast;
11use rustc_ast::visit;
12use rustc_crate_store::ExternCrate;
13use rustc_hir::Target;
14use rustc_hir::attrs::lang_items::{GenericRequirement, LangItem, LanguageItems};
15use rustc_hir::def_id::{DefId, LocalDefId};
16use rustc_middle::middle::resolve::ResolverAstLowering;
17use rustc_middle::query::Providers;
18use rustc_middle::ty::TyCtxt;
19use rustc_span::{Span, Symbol, sym};
20
21use crate::diagnostics::{DuplicateLangItem, IncorrectCrateType, IncorrectTarget};
22use crate::weak_lang_items;
23
24pub(crate) enum Duplicate {
25 Plain,
26 Crate,
27 CrateDepends,
28}
29
30struct LanguageItemCollector<'ast, 'tcx> {
31 items: LanguageItems,
32 tcx: TyCtxt<'tcx>,
33 resolver: &'ast ResolverAstLowering<'tcx>,
34 parent_item: Option<&'ast ast::Item>,
35}
36
37impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
38 fn new(
39 tcx: TyCtxt<'tcx>,
40 resolver: &'ast ResolverAstLowering<'tcx>,
41 ) -> LanguageItemCollector<'ast, 'tcx> {
42 LanguageItemCollector { tcx, resolver, items: LanguageItems::new(), parent_item: None }
43 }
44
45 fn check_for_lang(
46 &mut self,
47 actual_target: Target,
48 def_id: LocalDefId,
49 attrs: &'ast [ast::Attribute],
50 item_span: Span,
51 generics: Option<&'ast ast::Generics>,
52 ) {
53 if let Some((name, attr_span)) = extract_ast(attrs) {
54 match LangItem::from_name(name) {
55 Some(lang_item) => {
57 if actual_target != lang_item.target() {
58 if !(lang_item.is_weak()
61 && actual_target == Target::Fn
62 && lang_item.target() == Target::ForeignFn
63 && #[allow(non_exhaustive_omitted_patterns)] match lang_item {
LangItem::PanicImpl => true,
_ => false,
}matches!(lang_item, LangItem::PanicImpl))
64 {
65 self.tcx
66 .dcx()
67 .delayed_bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("lang item target is checked in attribute parser: {0:?} has {1} but expected {2}",
def_id, actual_target, lang_item.target()))
})format!("lang item target is checked in attribute parser: {:?} has {} but expected {}", def_id, actual_target, lang_item.target()));
68 return;
69 }
70 }
71 if lang_item.is_weak() && actual_target == Target::ForeignFn {
73 self.items.missing.push(lang_item);
74 } else {
75 self.collect_item_extended(
77 lang_item,
78 def_id,
79 item_span,
80 attr_span,
81 generics,
82 actual_target,
83 );
84 }
85 }
86 _ => {
88 self.tcx.dcx().delayed_bug("unknown lang item");
89 }
90 }
91 }
92 }
93
94 fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId, item_span: Option<Span>) {
95 if let Some(original_def_id) = self.items.get(lang_item)
97 && original_def_id != item_def_id
98 {
99 let lang_item_name = lang_item.name();
100 let crate_name = self.tcx.crate_name(item_def_id.krate);
101 let mut dependency_of = None;
102 let is_local = item_def_id.is_local();
103 let path = if is_local {
104 String::new()
105 } else {
106 self.tcx
107 .crate_extern_paths(item_def_id.krate)
108 .iter()
109 .map(|p| p.display().to_string())
110 .collect::<Vec<_>>()
111 .join(", ")
112 };
113
114 let mut orig_crate_name = None;
115 let mut orig_dependency_of = None;
116 let orig_is_local = original_def_id.is_local();
117 let orig_path = if orig_is_local {
118 String::new()
119 } else {
120 self.tcx
121 .crate_extern_paths(original_def_id.krate)
122 .iter()
123 .map(|p| p.display().to_string())
124 .collect::<Vec<_>>()
125 .join(", ")
126 };
127
128 if !original_def_id.is_local() {
129 orig_crate_name = Some(self.tcx.crate_name(original_def_id.krate));
130 if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) =
131 self.tcx.extern_crate(original_def_id.krate)
132 {
133 orig_dependency_of = Some(self.tcx.crate_name(*inner_dependency_of));
134 }
135 }
136
137 let duplicate = if item_span.is_some() {
138 Duplicate::Plain
139 } else {
140 match self.tcx.extern_crate(item_def_id.krate) {
141 Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => {
142 dependency_of = Some(self.tcx.crate_name(*inner_dependency_of));
143 Duplicate::CrateDepends
144 }
145 _ => Duplicate::Crate,
146 }
147 };
148
149 self.tcx.dcx().emit_fatal(DuplicateLangItem {
153 local_span: item_span,
154 lang_item_name,
155 crate_name,
156 dependency_of,
157 is_local,
158 path,
159 first_defined_span: original_def_id.as_local().map(|did| self.tcx.source_span(did)),
160 orig_crate_name,
161 orig_dependency_of,
162 orig_is_local,
163 orig_path,
164 duplicate,
165 });
166 } else {
167 self.items.set(lang_item, item_def_id);
169 }
170 }
171
172 fn collect_item_extended(
175 &mut self,
176 lang_item: LangItem,
177 item_def_id: LocalDefId,
178 item_span: Span,
179 attr_span: Span,
180 generics: Option<&'ast ast::Generics>,
181 target: Target,
182 ) {
183 let name = lang_item.name();
184
185 if let Some(generics) = generics {
186 let mut actual_num = generics.params.len();
196 if target.is_associated_item() {
197 actual_num += self
198 .parent_item
199 .unwrap()
200 .opt_generics()
201 .map_or(0, |generics| generics.params.len());
202 }
203
204 let mut at_least = false;
205 let required = match lang_item.required_generics() {
206 GenericRequirement::Exact(num) if num != actual_num => Some(num),
207 GenericRequirement::Minimum(num) if actual_num < num => {
208 at_least = true;
209 Some(num)
210 }
211 _ => None,
213 };
214
215 if let Some(num) = required {
216 self.tcx.dcx().emit_err(IncorrectTarget {
220 span: attr_span,
221 generics_span: generics.span,
222 name: name.as_str(),
223 kind: target.name(),
224 num,
225 actual_num,
226 at_least,
227 });
228
229 return;
231 }
232 }
233
234 if self.tcx.crate_types().contains(&rustc_structures::CrateType::Sdylib) {
235 self.tcx.dcx().emit_err(IncorrectCrateType { span: attr_span });
236 }
237
238 self.collect_item(lang_item, item_def_id.to_def_id(), Some(item_span));
239 }
240}
241
242fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
244 let (resolver, krate) = tcx.resolver_for_lowering();
245 let resolver = &*resolver.borrow();
246 let krate = &*krate.borrow();
247
248 let mut collector = LanguageItemCollector::new(tcx, resolver);
250
251 for &cnum in tcx.used_crates(()).iter() {
253 for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() {
254 collector.collect_item(lang_item, def_id, None);
255 }
256 }
257
258 visit::Visitor::visit_crate(&mut collector, krate);
260
261 weak_lang_items::check_crate(tcx, &mut collector.items);
263
264 collector.items
266}
267
268impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
269 fn visit_item(&mut self, i: &'ast ast::Item) {
270 let target = Target::from_ast_item(i);
271
272 self.check_for_lang(
273 target,
274 self.resolver.owners[&i.id].def_id,
275 &i.attrs,
276 i.span,
277 i.opt_generics(),
278 );
279
280 let parent_item = self.parent_item.replace(i);
281 visit::walk_item(self, i);
282 self.parent_item = parent_item;
283 }
284
285 fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) {
286 self.check_for_lang(
287 Target::from_foreign_item_kind(&i.kind),
288 self.resolver.owners[&i.id].def_id,
289 &i.attrs,
290 i.span,
291 None,
292 );
293 }
294
295 fn visit_variant(&mut self, variant: &'ast ast::Variant) {
296 self.check_for_lang(
297 Target::Variant,
298 self.resolver.owners[&self.parent_item.unwrap().id].node_id_to_def_id[&variant.id],
299 &variant.attrs,
300 variant.span,
301 None,
302 );
303 }
304
305 fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) {
306 let target = Target::from_assoc_item_kind(&i.kind, ctxt);
307 let generics = i.opt_generics();
308
309 self.check_for_lang(target, self.resolver.owners[&i.id].def_id, &i.attrs, i.span, generics);
310
311 visit::walk_assoc_item(self, i, ctxt);
312 }
313}
314
315pub(crate) fn extract_ast(attrs: &[rustc_ast::ast::Attribute]) -> Option<(Symbol, Span)> {
320 attrs.iter().find_map(|attr| {
321 Some(match attr {
322 _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()),
323 _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()),
324 _ => return None,
325 })
326 })
327}
328
329pub(crate) fn provide(providers: &mut Providers) {
330 providers.get_lang_items = get_lang_items;
331}