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