1use rustc_ast as ast;
11use rustc_attr_ir::target::Target;
12use rustc_attr_ir::{GenericRequirement, LangItem, LanguageItems};
13use rustc_crate_store::ExternCrate;
14use rustc_hir::def_id::{DefId, LocalDefId};
15use rustc_middle::ty::TyCtxt;
16use rustc_span::{Span, sym};
17use rustc_structures::CrateType;
18
19use crate::diagnostics::{DuplicateLangItem, IncorrectCrateType, IncorrectTarget};
20use crate::late::{LateResolutionVisitor, RibKind};
21
22pub(crate) enum Duplicate {
23 Plain,
24 Crate,
25 CrateDepends,
26}
27
28impl<'tcx> LateResolutionVisitor<'_, '_, '_, 'tcx> {
29 pub(super) fn check_for_lang(
30 &mut self,
31 actual_target: Target,
32 def_id: LocalDefId,
33 attrs: &[ast::Attribute],
34 item_span: Span,
35 generics: Option<&ast::Generics>,
36 ) {
37 let attrs = attrs.iter().find_map(|attr| {
38 Some(match attr {
39 _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
40 _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
41 _ => return None,
42 })
43 });
44 if let Some((name, attr_span)) = attrs {
45 match LangItem::from_name(name) {
46 Some(lang_item) => {
48 if actual_target != lang_item.target() {
49 if !(lang_item.is_weak()
52 && actual_target == Target::Fn
53 && lang_item.target() == Target::ForeignFn
54 && #[allow(non_exhaustive_omitted_patterns)] match lang_item {
LangItem::PanicImpl => true,
_ => false,
}matches!(lang_item, LangItem::PanicImpl))
55 {
56 self.r.tcx
57 .dcx()
58 .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()));
59 return;
60 }
61 }
62 if lang_item.is_weak() && actual_target == Target::ForeignFn {
64 self.r.lang_items.missing.push(lang_item);
65 } else {
66 self.collect_item_extended(
68 lang_item,
69 def_id,
70 item_span,
71 attr_span,
72 generics,
73 actual_target,
74 );
75 }
76 }
77 _ => {
79 self.r.tcx.dcx().delayed_bug("unknown lang item");
80 }
81 }
82 }
83 }
84
85 fn collect_item_extended(
88 &mut self,
89 lang_item: LangItem,
90 item_def_id: LocalDefId,
91 item_span: Span,
92 attr_span: Span,
93 generics: Option<&ast::Generics>,
94 target: Target,
95 ) {
96 let name = lang_item.name();
97
98 if let Some(generics) = generics {
99 let mut actual_num = generics.params.len();
109 if target.is_associated_item() {
110 for rib in self.ribs.type_ns.iter().rev() {
111 match rib.kind {
112 RibKind::Item(_, _) => {
113 actual_num += rib.bindings.len();
114 break;
115 }
116 _ => {}
117 }
118 }
119 }
120
121 let mut at_least = false;
122 let required = match lang_item.required_generics() {
123 GenericRequirement::Exact(num) if num != actual_num => Some(num),
124 GenericRequirement::Minimum(num) if actual_num < num => {
125 at_least = true;
126 Some(num)
127 }
128 _ => None,
130 };
131
132 if let Some(num) = required {
133 self.r.tcx.dcx().emit_err(IncorrectTarget {
137 span: attr_span,
138 generics_span: generics.span,
139 name: name.as_str(),
140 kind: target.name(),
141 num,
142 actual_num,
143 at_least,
144 });
145
146 return;
148 }
149 }
150
151 if self.r.tcx.crate_types().contains(&CrateType::Sdylib) {
152 self.r.tcx.dcx().emit_err(IncorrectCrateType { span: attr_span });
153 }
154
155 collect_item(
156 self.r.tcx,
157 &mut self.r.lang_items,
158 lang_item,
159 item_def_id.to_def_id(),
160 Some(item_span),
161 );
162 }
163}
164
165pub(crate) fn collect_item(
166 tcx: TyCtxt<'_>,
167 lang_items: &mut LanguageItems,
168 lang_item: LangItem,
169 item_def_id: DefId,
170 item_span: Option<Span>,
171) {
172 if let Some(original_def_id) = lang_items.get(lang_item)
174 && original_def_id != item_def_id
175 {
176 let (item_def_id, original_def_id, item_span) = if let Some(original_def_id) =
177 original_def_id.as_local()
178 && !item_def_id.is_local()
179 {
180 (original_def_id.to_def_id(), item_def_id, Some(tcx.source_span(original_def_id)))
184 } else {
185 (item_def_id, original_def_id, item_span)
186 };
187 let lang_item_name = lang_item.name();
188 let crate_name = tcx.crate_name(item_def_id.krate);
189 let mut dependency_of = None;
190 let is_local = item_def_id.is_local();
191 let path = if is_local {
192 String::new()
193 } else {
194 tcx.crate_extern_paths(item_def_id.krate)
195 .iter()
196 .map(|p| p.display().to_string())
197 .collect::<Vec<_>>()
198 .join(", ")
199 };
200
201 let mut orig_crate_name = None;
202 let mut orig_dependency_of = None;
203 let orig_is_local = original_def_id.is_local();
204 let orig_path = if orig_is_local {
205 String::new()
206 } else {
207 tcx.crate_extern_paths(original_def_id.krate)
208 .iter()
209 .map(|p| p.display().to_string())
210 .collect::<Vec<_>>()
211 .join(", ")
212 };
213
214 if !original_def_id.is_local() {
215 orig_crate_name = Some(tcx.crate_name(original_def_id.krate));
216 if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) =
217 tcx.extern_crate(original_def_id.krate)
218 {
219 orig_dependency_of = Some(tcx.crate_name(*inner_dependency_of));
220 }
221 }
222
223 let duplicate = if item_span.is_some() {
224 Duplicate::Plain
225 } else {
226 match tcx.extern_crate(item_def_id.krate) {
227 Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => {
228 dependency_of = Some(tcx.crate_name(*inner_dependency_of));
229 Duplicate::CrateDepends
230 }
231 _ => Duplicate::Crate,
232 }
233 };
234
235 tcx.dcx().emit_fatal(DuplicateLangItem {
239 local_span: item_span,
240 lang_item_name,
241 crate_name,
242 dependency_of,
243 is_local,
244 path,
245 first_defined_span: original_def_id.as_local().map(|did| tcx.source_span(did)),
246 orig_crate_name,
247 orig_dependency_of,
248 orig_is_local,
249 orig_path,
250 duplicate,
251 });
252 } else {
253 lang_items.set(lang_item, item_def_id);
255 }
256}