]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / compiler / rustc_codegen_ssa / src / codegen_attrs.rs
1 use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
2 use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
3 use rustc_errors::struct_span_err;
4 use rustc_hir as hir;
5 use rustc_hir::def::DefKind;
6 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
7 use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
8 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
9 use rustc_middle::mir::mono::Linkage;
10 use rustc_middle::ty::query::Providers;
11 use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
12 use rustc_session::{lint, parse::feature_err};
13 use rustc_span::{sym, Span};
14 use rustc_target::spec::{abi, SanitizerSet};
15
16 use crate::target_features::from_target_feature;
17 use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
18
19 fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
20     use rustc_middle::mir::mono::Linkage::*;
21
22     // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
23     // applicable to variable declarations and may not really make sense for
24     // Rust code in the first place but allow them anyway and trust that the
25     // user knows what they're doing. Who knows, unanticipated use cases may pop
26     // up in the future.
27     //
28     // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
29     // and don't have to be, LLVM treats them as no-ops.
30     match name {
31         "appending" => Appending,
32         "available_externally" => AvailableExternally,
33         "common" => Common,
34         "extern_weak" => ExternalWeak,
35         "external" => External,
36         "internal" => Internal,
37         "linkonce" => LinkOnceAny,
38         "linkonce_odr" => LinkOnceODR,
39         "private" => Private,
40         "weak" => WeakAny,
41         "weak_odr" => WeakODR,
42         _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
43     }
44 }
45
46 fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
47     if cfg!(debug_assertions) {
48         let def_kind = tcx.def_kind(did);
49         assert!(
50             def_kind.has_codegen_attrs(),
51             "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
52         );
53     }
54
55     let did = did.expect_local();
56     let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
57     let mut codegen_fn_attrs = CodegenFnAttrs::new();
58     if tcx.should_inherit_track_caller(did) {
59         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
60     }
61
62     let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
63
64     // In some cases, attribute are only valid on functions, but it's the `check_attr`
65     // pass that check that they aren't used anywhere else, rather this module.
66     // In these cases, we bail from performing further checks that are only meaningful for
67     // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
68     // report a delayed bug, just in case `check_attr` isn't doing its job.
69     let validate_fn_only_attr = |attr_sp| -> bool {
70         let def_kind = tcx.def_kind(did);
71         if let DefKind::Fn | DefKind::AssocFn | DefKind::Variant | DefKind::Ctor(..) = def_kind {
72             true
73         } else {
74             tcx.sess.delay_span_bug(attr_sp, "this attribute can only be applied to functions");
75             false
76         }
77     };
78
79     let mut inline_span = None;
80     let mut link_ordinal_span = None;
81     let mut no_sanitize_span = None;
82     for attr in attrs.iter() {
83         if attr.has_name(sym::cold) {
84             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
85         } else if attr.has_name(sym::rustc_allocator) {
86             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
87         } else if attr.has_name(sym::ffi_returns_twice) {
88             codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
89         } else if attr.has_name(sym::ffi_pure) {
90             codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
91         } else if attr.has_name(sym::ffi_const) {
92             codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
93         } else if attr.has_name(sym::rustc_nounwind) {
94             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
95         } else if attr.has_name(sym::rustc_reallocator) {
96             codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
97         } else if attr.has_name(sym::rustc_deallocator) {
98             codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
99         } else if attr.has_name(sym::rustc_allocator_zeroed) {
100             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
101         } else if attr.has_name(sym::naked) {
102             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
103         } else if attr.has_name(sym::no_mangle) {
104             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
105         } else if attr.has_name(sym::no_coverage) {
106             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
107         } else if attr.has_name(sym::rustc_std_internal_symbol) {
108             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
109         } else if attr.has_name(sym::used) {
110             let inner = attr.meta_item_list();
111             match inner.as_deref() {
112                 Some([item]) if item.has_name(sym::linker) => {
113                     if !tcx.features().used_with_arg {
114                         feature_err(
115                             &tcx.sess.parse_sess,
116                             sym::used_with_arg,
117                             attr.span,
118                             "`#[used(linker)]` is currently unstable",
119                         )
120                         .emit();
121                     }
122                     codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
123                 }
124                 Some([item]) if item.has_name(sym::compiler) => {
125                     if !tcx.features().used_with_arg {
126                         feature_err(
127                             &tcx.sess.parse_sess,
128                             sym::used_with_arg,
129                             attr.span,
130                             "`#[used(compiler)]` is currently unstable",
131                         )
132                         .emit();
133                     }
134                     codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
135                 }
136                 Some(_) => {
137                     tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
138                 }
139                 None => {
140                     // Unfortunately, unconditionally using `llvm.used` causes
141                     // issues in handling `.init_array` with the gold linker,
142                     // but using `llvm.compiler.used` caused a nontrival amount
143                     // of unintentional ecosystem breakage -- particularly on
144                     // Mach-O targets.
145                     //
146                     // As a result, we emit `llvm.compiler.used` only on ELF
147                     // targets. This is somewhat ad-hoc, but actually follows
148                     // our pre-LLVM 13 behavior (prior to the ecosystem
149                     // breakage), and seems to match `clang`'s behavior as well
150                     // (both before and after LLVM 13), possibly because they
151                     // have similar compatibility concerns to us. See
152                     // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
153                     // and following comments for some discussion of this, as
154                     // well as the comments in `rustc_codegen_llvm` where these
155                     // flags are handled.
156                     //
157                     // Anyway, to be clear: this is still up in the air
158                     // somewhat, and is subject to change in the future (which
159                     // is a good thing, because this would ideally be a bit
160                     // more firmed up).
161                     let is_like_elf = !(tcx.sess.target.is_like_osx
162                         || tcx.sess.target.is_like_windows
163                         || tcx.sess.target.is_like_wasm);
164                     codegen_fn_attrs.flags |= if is_like_elf {
165                         CodegenFnAttrFlags::USED
166                     } else {
167                         CodegenFnAttrFlags::USED_LINKER
168                     };
169                 }
170             }
171         } else if attr.has_name(sym::cmse_nonsecure_entry) {
172             if validate_fn_only_attr(attr.span)
173                 && !matches!(tcx.fn_sig(did).skip_binder().abi(), abi::Abi::C { .. })
174             {
175                 struct_span_err!(
176                     tcx.sess,
177                     attr.span,
178                     E0776,
179                     "`#[cmse_nonsecure_entry]` requires C ABI"
180                 )
181                 .emit();
182             }
183             if !tcx.sess.target.llvm_target.contains("thumbv8m") {
184                 struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
185                     .emit();
186             }
187             codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
188         } else if attr.has_name(sym::thread_local) {
189             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
190         } else if attr.has_name(sym::track_caller) {
191             if !tcx.is_closure(did.to_def_id())
192                 && validate_fn_only_attr(attr.span)
193                 && tcx.fn_sig(did).skip_binder().abi() != abi::Abi::Rust
194             {
195                 struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
196                     .emit();
197             }
198             if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
199                 feature_err(
200                     &tcx.sess.parse_sess,
201                     sym::closure_track_caller,
202                     attr.span,
203                     "`#[track_caller]` on closures is currently unstable",
204                 )
205                 .emit();
206             }
207             codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
208         } else if attr.has_name(sym::export_name) {
209             if let Some(s) = attr.value_str() {
210                 if s.as_str().contains('\0') {
211                     // `#[export_name = ...]` will be converted to a null-terminated string,
212                     // so it may not contain any null characters.
213                     struct_span_err!(
214                         tcx.sess,
215                         attr.span,
216                         E0648,
217                         "`export_name` may not contain null characters"
218                     )
219                     .emit();
220                 }
221                 codegen_fn_attrs.export_name = Some(s);
222             }
223         } else if attr.has_name(sym::target_feature) {
224             if !tcx.is_closure(did.to_def_id())
225                 && tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal
226             {
227                 if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
228                     // The `#[target_feature]` attribute is allowed on
229                     // WebAssembly targets on all functions, including safe
230                     // ones. Other targets require that `#[target_feature]` is
231                     // only applied to unsafe functions (pending the
232                     // `target_feature_11` feature) because on most targets
233                     // execution of instructions that are not supported is
234                     // considered undefined behavior. For WebAssembly which is a
235                     // 100% safe target at execution time it's not possible to
236                     // execute undefined instructions, and even if a future
237                     // feature was added in some form for this it would be a
238                     // deterministic trap. There is no undefined behavior when
239                     // executing WebAssembly so `#[target_feature]` is allowed
240                     // on safe functions (but again, only for WebAssembly)
241                     //
242                     // Note that this is also allowed if `actually_rustdoc` so
243                     // if a target is documenting some wasm-specific code then
244                     // it's not spuriously denied.
245                 } else if !tcx.features().target_feature_11 {
246                     let mut err = feature_err(
247                         &tcx.sess.parse_sess,
248                         sym::target_feature_11,
249                         attr.span,
250                         "`#[target_feature(..)]` can only be applied to `unsafe` functions",
251                     );
252                     err.span_label(tcx.def_span(did), "not an `unsafe` function");
253                     err.emit();
254                 } else {
255                     check_target_feature_trait_unsafe(tcx, did, attr.span);
256                 }
257             }
258             from_target_feature(
259                 tcx,
260                 attr,
261                 supported_target_features,
262                 &mut codegen_fn_attrs.target_features,
263             );
264         } else if attr.has_name(sym::linkage) {
265             if let Some(val) = attr.value_str() {
266                 let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
267                 if tcx.is_foreign_item(did) {
268                     codegen_fn_attrs.import_linkage = linkage;
269                 } else {
270                     codegen_fn_attrs.linkage = linkage;
271                 }
272             }
273         } else if attr.has_name(sym::link_section) {
274             if let Some(val) = attr.value_str() {
275                 if val.as_str().bytes().any(|b| b == 0) {
276                     let msg = format!(
277                         "illegal null byte in link_section \
278                          value: `{}`",
279                         &val
280                     );
281                     tcx.sess.span_err(attr.span, &msg);
282                 } else {
283                     codegen_fn_attrs.link_section = Some(val);
284                 }
285             }
286         } else if attr.has_name(sym::link_name) {
287             codegen_fn_attrs.link_name = attr.value_str();
288         } else if attr.has_name(sym::link_ordinal) {
289             link_ordinal_span = Some(attr.span);
290             if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
291                 codegen_fn_attrs.link_ordinal = ordinal;
292             }
293         } else if attr.has_name(sym::no_sanitize) {
294             no_sanitize_span = Some(attr.span);
295             if let Some(list) = attr.meta_item_list() {
296                 for item in list.iter() {
297                     if item.has_name(sym::address) {
298                         codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
299                     } else if item.has_name(sym::cfi) {
300                         codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
301                     } else if item.has_name(sym::kcfi) {
302                         codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
303                     } else if item.has_name(sym::memory) {
304                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
305                     } else if item.has_name(sym::memtag) {
306                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
307                     } else if item.has_name(sym::shadow_call_stack) {
308                         codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
309                     } else if item.has_name(sym::thread) {
310                         codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
311                     } else if item.has_name(sym::hwaddress) {
312                         codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
313                     } else {
314                         tcx.sess
315                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
316                             .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
317                             .emit();
318                     }
319                 }
320             }
321         } else if attr.has_name(sym::instruction_set) {
322             codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] {
323                 [NestedMetaItem::MetaItem(set)] => {
324                     let segments =
325                         set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
326                     match segments.as_slice() {
327                         [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
328                             if !tcx.sess.target.has_thumb_interworking {
329                                 struct_span_err!(
330                                     tcx.sess.diagnostic(),
331                                     attr.span,
332                                     E0779,
333                                     "target does not support `#[instruction_set]`"
334                                 )
335                                 .emit();
336                                 None
337                             } else if segments[1] == sym::a32 {
338                                 Some(InstructionSetAttr::ArmA32)
339                             } else if segments[1] == sym::t32 {
340                                 Some(InstructionSetAttr::ArmT32)
341                             } else {
342                                 unreachable!()
343                             }
344                         }
345                         _ => {
346                             struct_span_err!(
347                                 tcx.sess.diagnostic(),
348                                 attr.span,
349                                 E0779,
350                                 "invalid instruction set specified",
351                             )
352                             .emit();
353                             None
354                         }
355                     }
356                 }
357                 [] => {
358                     struct_span_err!(
359                         tcx.sess.diagnostic(),
360                         attr.span,
361                         E0778,
362                         "`#[instruction_set]` requires an argument"
363                     )
364                     .emit();
365                     None
366                 }
367                 _ => {
368                     struct_span_err!(
369                         tcx.sess.diagnostic(),
370                         attr.span,
371                         E0779,
372                         "cannot specify more than one instruction set"
373                     )
374                     .emit();
375                     None
376                 }
377             })
378         } else if attr.has_name(sym::repr) {
379             codegen_fn_attrs.alignment = match attr.meta_item_list() {
380                 Some(items) => match items.as_slice() {
381                     [item] => match item.name_value_literal() {
382                         Some((sym::align, literal)) => {
383                             let alignment = rustc_attr::parse_alignment(&literal.kind);
384
385                             match alignment {
386                                 Ok(align) => Some(align),
387                                 Err(msg) => {
388                                     struct_span_err!(
389                                         tcx.sess.diagnostic(),
390                                         attr.span,
391                                         E0589,
392                                         "invalid `repr(align)` attribute: {}",
393                                         msg
394                                     )
395                                     .emit();
396
397                                     None
398                                 }
399                             }
400                         }
401                         _ => None,
402                     },
403                     [] => None,
404                     _ => None,
405                 },
406                 None => None,
407             };
408         }
409     }
410
411     codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
412         if !attr.has_name(sym::inline) {
413             return ia;
414         }
415         match attr.meta_kind() {
416             Some(MetaItemKind::Word) => InlineAttr::Hint,
417             Some(MetaItemKind::List(ref items)) => {
418                 inline_span = Some(attr.span);
419                 if items.len() != 1 {
420                     struct_span_err!(
421                         tcx.sess.diagnostic(),
422                         attr.span,
423                         E0534,
424                         "expected one argument"
425                     )
426                     .emit();
427                     InlineAttr::None
428                 } else if list_contains_name(&items, sym::always) {
429                     InlineAttr::Always
430                 } else if list_contains_name(&items, sym::never) {
431                     InlineAttr::Never
432                 } else {
433                     struct_span_err!(
434                         tcx.sess.diagnostic(),
435                         items[0].span(),
436                         E0535,
437                         "invalid argument"
438                     )
439                     .help("valid inline arguments are `always` and `never`")
440                     .emit();
441
442                     InlineAttr::None
443                 }
444             }
445             Some(MetaItemKind::NameValue(_)) => ia,
446             None => ia,
447         }
448     });
449
450     codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
451         if !attr.has_name(sym::optimize) {
452             return ia;
453         }
454         let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
455         match attr.meta_kind() {
456             Some(MetaItemKind::Word) => {
457                 err(attr.span, "expected one argument");
458                 ia
459             }
460             Some(MetaItemKind::List(ref items)) => {
461                 inline_span = Some(attr.span);
462                 if items.len() != 1 {
463                     err(attr.span, "expected one argument");
464                     OptimizeAttr::None
465                 } else if list_contains_name(&items, sym::size) {
466                     OptimizeAttr::Size
467                 } else if list_contains_name(&items, sym::speed) {
468                     OptimizeAttr::Speed
469                 } else {
470                     err(items[0].span(), "invalid argument");
471                     OptimizeAttr::None
472                 }
473             }
474             Some(MetaItemKind::NameValue(_)) => ia,
475             None => ia,
476         }
477     });
478
479     // #73631: closures inherit `#[target_feature]` annotations
480     if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
481         let owner_id = tcx.parent(did.to_def_id());
482         if tcx.def_kind(owner_id).has_codegen_attrs() {
483             codegen_fn_attrs
484                 .target_features
485                 .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
486         }
487     }
488
489     // If a function uses #[target_feature] it can't be inlined into general
490     // purpose functions as they wouldn't have the right target features
491     // enabled. For that reason we also forbid #[inline(always)] as it can't be
492     // respected.
493     if !codegen_fn_attrs.target_features.is_empty() {
494         if codegen_fn_attrs.inline == InlineAttr::Always {
495             if let Some(span) = inline_span {
496                 tcx.sess.span_err(
497                     span,
498                     "cannot use `#[inline(always)]` with \
499                      `#[target_feature]`",
500                 );
501             }
502         }
503     }
504
505     if !codegen_fn_attrs.no_sanitize.is_empty() {
506         if codegen_fn_attrs.inline == InlineAttr::Always {
507             if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
508                 let hir_id = tcx.hir().local_def_id_to_hir_id(did);
509                 tcx.struct_span_lint_hir(
510                     lint::builtin::INLINE_NO_SANITIZE,
511                     hir_id,
512                     no_sanitize_span,
513                     "`no_sanitize` will have no effect after inlining",
514                     |lint| lint.span_note(inline_span, "inlining requested here"),
515                 )
516             }
517         }
518     }
519
520     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
521         codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
522         codegen_fn_attrs.inline = InlineAttr::Never;
523     }
524
525     // Weak lang items have the same semantics as "std internal" symbols in the
526     // sense that they're preserved through all our LTO passes and only
527     // strippable by the linker.
528     //
529     // Additionally weak lang items have predetermined symbol names.
530     if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
531         codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
532     }
533     if let Some((name, _)) = lang_items::extract(attrs)
534         && let Some(lang_item) = LangItem::from_name(name)
535         && let Some(link_name) = lang_item.link_name()
536     {
537         codegen_fn_attrs.export_name = Some(link_name);
538         codegen_fn_attrs.link_name = Some(link_name);
539     }
540     check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
541
542     // Internal symbols to the standard library all have no_mangle semantics in
543     // that they have defined symbol names present in the function name. This
544     // also applies to weak symbols where they all have known symbol names.
545     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
546         codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
547     }
548
549     // Any linkage to LLVM intrinsics for now forcibly marks them all as never
550     // unwinds since LLVM sometimes can't handle codegen which `invoke`s
551     // intrinsic functions.
552     if let Some(name) = &codegen_fn_attrs.link_name {
553         if name.as_str().starts_with("llvm.") {
554             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
555         }
556     }
557
558     codegen_fn_attrs
559 }
560
561 /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
562 /// applied to the method prototype.
563 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
564     if let Some(impl_item) = tcx.opt_associated_item(def_id)
565         && let ty::AssocItemContainer::ImplContainer = impl_item.container
566         && let Some(trait_item) = impl_item.trait_item_def_id
567     {
568         return tcx
569             .codegen_fn_attrs(trait_item)
570             .flags
571             .intersects(CodegenFnAttrFlags::TRACK_CALLER);
572     }
573
574     false
575 }
576
577 fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
578     use rustc_ast::{LitIntType, LitKind, MetaItemLit};
579     if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
580         feature_err(
581             &tcx.sess.parse_sess,
582             sym::raw_dylib,
583             attr.span,
584             "`#[link_ordinal]` is unstable on x86",
585         )
586         .emit();
587     }
588     let meta_item_list = attr.meta_item_list();
589     let meta_item_list = meta_item_list.as_deref();
590     let sole_meta_list = match meta_item_list {
591         Some([item]) => item.lit(),
592         Some(_) => {
593             tcx.sess
594                 .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
595                 .note("the attribute requires exactly one argument")
596                 .emit();
597             return None;
598         }
599         _ => None,
600     };
601     if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
602         sole_meta_list
603     {
604         // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
605         // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
606         // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
607         // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
608         //
609         // FIXME: should we allow an ordinal of 0?  The MSVC toolchain has inconsistent support for this:
610         // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
611         // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
612         // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
613         // library produced by LLVM with an ordinal of 0, and it generates an .EXE.  (I don't know yet
614         // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
615         // about LINK.EXE failing.)
616         if *ordinal <= u16::MAX as u128 {
617             Some(*ordinal as u16)
618         } else {
619             let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
620             tcx.sess
621                 .struct_span_err(attr.span, &msg)
622                 .note("the value may not exceed `u16::MAX`")
623                 .emit();
624             None
625         }
626     } else {
627         tcx.sess
628             .struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
629             .note("an unsuffixed integer value, e.g., `1`, is expected")
630             .emit();
631         None
632     }
633 }
634
635 fn check_link_name_xor_ordinal(
636     tcx: TyCtxt<'_>,
637     codegen_fn_attrs: &CodegenFnAttrs,
638     inline_span: Option<Span>,
639 ) {
640     if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
641         return;
642     }
643     let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
644     if let Some(span) = inline_span {
645         tcx.sess.span_err(span, msg);
646     } else {
647         tcx.sess.err(msg);
648     }
649 }
650
651 pub fn provide(providers: &mut Providers) {
652     *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
653 }