2025-01-29 21:31:13 -05:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
2025-02-05 12:22:28 -08:00
|
|
|
use rustc_abi::ExternAbi;
|
2025-03-07 17:37:50 +01:00
|
|
|
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
|
2025-04-03 17:21:21 -04:00
|
|
|
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
|
2025-02-09 22:49:33 +01:00
|
|
|
use rustc_attr_parsing::ReprAttr::ReprAlign;
|
|
|
|
use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
|
2024-09-11 13:57:12 +01:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2022-12-12 03:07:44 -08:00
|
|
|
use rustc_hir::def::DefKind;
|
2022-12-08 03:53:35 +00:00
|
|
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
|
|
|
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
|
2024-10-17 01:14:01 +02:00
|
|
|
use rustc_hir::{self as hir, HirId, LangItem, lang_items};
|
2023-12-12 13:37:04 -08:00
|
|
|
use rustc_middle::middle::codegen_fn_attrs::{
|
2024-09-01 16:35:53 +02:00
|
|
|
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
|
2023-12-12 13:37:04 -08:00
|
|
|
};
|
2022-12-08 03:53:35 +00:00
|
|
|
use rustc_middle::mir::mono::Linkage;
|
2023-05-15 06:24:45 +02:00
|
|
|
use rustc_middle::query::Providers;
|
2025-01-29 21:31:13 -05:00
|
|
|
use rustc_middle::span_bug;
|
2023-02-22 19:51:17 +04:00
|
|
|
use rustc_middle::ty::{self as ty, TyCtxt};
|
2022-12-08 03:53:35 +00:00
|
|
|
use rustc_session::parse::feature_err;
|
2024-09-11 13:57:12 +01:00
|
|
|
use rustc_session::{Session, lint};
|
2024-12-13 10:29:23 +11:00
|
|
|
use rustc_span::{Ident, Span, sym};
|
2025-02-05 12:22:28 -08:00
|
|
|
use rustc_target::spec::SanitizerSet;
|
2024-09-23 18:46:23 +01:00
|
|
|
use tracing::debug;
|
2022-12-08 03:53:35 +00:00
|
|
|
|
2024-09-02 11:45:59 +02:00
|
|
|
use crate::errors;
|
|
|
|
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
|
2022-12-08 03:53:35 +00:00
|
|
|
|
|
|
|
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
|
|
|
use rustc_middle::mir::mono::Linkage::*;
|
|
|
|
|
|
|
|
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
|
|
|
|
// applicable to variable declarations and may not really make sense for
|
|
|
|
// Rust code in the first place but allow them anyway and trust that the
|
|
|
|
// user knows what they're doing. Who knows, unanticipated use cases may pop
|
|
|
|
// up in the future.
|
|
|
|
//
|
|
|
|
// ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
|
|
|
|
// and don't have to be, LLVM treats them as no-ops.
|
|
|
|
match name {
|
|
|
|
"available_externally" => AvailableExternally,
|
|
|
|
"common" => Common,
|
|
|
|
"extern_weak" => ExternalWeak,
|
|
|
|
"external" => External,
|
|
|
|
"internal" => Internal,
|
|
|
|
"linkonce" => LinkOnceAny,
|
|
|
|
"linkonce_odr" => LinkOnceODR,
|
|
|
|
"weak" => WeakAny,
|
|
|
|
"weak_odr" => WeakODR,
|
2023-12-18 22:21:37 +11:00
|
|
|
_ => tcx.dcx().span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-13 18:54:05 +00:00
|
|
|
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
2022-12-08 03:53:35 +00:00
|
|
|
if cfg!(debug_assertions) {
|
|
|
|
let def_kind = tcx.def_kind(did);
|
|
|
|
assert!(
|
|
|
|
def_kind.has_codegen_attrs(),
|
|
|
|
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2025-02-21 18:33:05 +11:00
|
|
|
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did));
|
2022-12-08 03:53:35 +00:00
|
|
|
let mut codegen_fn_attrs = CodegenFnAttrs::new();
|
|
|
|
if tcx.should_inherit_track_caller(did) {
|
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
|
|
|
}
|
|
|
|
|
2025-01-29 21:31:13 -05:00
|
|
|
// If our rustc version supports autodiff/enzyme, then we call our handler
|
|
|
|
// to check for any `#[rustc_autodiff(...)]` attributes.
|
|
|
|
if cfg!(llvm_enzyme) {
|
|
|
|
let ad = autodiff_attrs(tcx, did.into());
|
|
|
|
codegen_fn_attrs.autodiff_item = ad;
|
|
|
|
}
|
|
|
|
|
2023-07-18 22:15:47 +08:00
|
|
|
// When `no_builtins` is applied at the crate level, we should add the
|
|
|
|
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
2025-02-21 18:33:05 +11:00
|
|
|
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
2023-07-18 22:15:47 +08:00
|
|
|
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
|
|
|
if no_builtins {
|
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
|
|
|
}
|
|
|
|
|
2024-09-02 11:45:59 +02:00
|
|
|
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
|
2022-12-08 03:53:35 +00:00
|
|
|
|
|
|
|
let mut inline_span = None;
|
|
|
|
let mut link_ordinal_span = None;
|
|
|
|
let mut no_sanitize_span = None;
|
2024-10-09 14:24:15 +02:00
|
|
|
let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
|
2023-03-13 18:32:25 +00:00
|
|
|
|
2022-12-08 03:53:35 +00:00
|
|
|
for attr in attrs.iter() {
|
2023-03-13 18:32:25 +00:00
|
|
|
// In some cases, attribute are only valid on functions, but it's the `check_attr`
|
|
|
|
// pass that check that they aren't used anywhere else, rather this module.
|
|
|
|
// In these cases, we bail from performing further checks that are only meaningful for
|
|
|
|
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
|
|
|
|
// report a delayed bug, just in case `check_attr` isn't doing its job.
|
|
|
|
let fn_sig = || {
|
2024-09-01 16:35:53 +02:00
|
|
|
use DefKind::*;
|
|
|
|
|
|
|
|
let def_kind = tcx.def_kind(did);
|
|
|
|
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
|
|
|
|
Some(tcx.fn_sig(did))
|
|
|
|
} else {
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().span_delayed_bug(
|
|
|
|
attr.span(),
|
|
|
|
"this attribute can only be applied to functions",
|
|
|
|
);
|
2024-09-01 16:35:53 +02:00
|
|
|
None
|
2023-03-13 18:32:25 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2025-02-09 22:49:33 +01:00
|
|
|
if let hir::Attribute::Parsed(p) = attr {
|
|
|
|
match p {
|
|
|
|
AttributeKind::Repr(reprs) => {
|
|
|
|
codegen_fn_attrs.alignment = reprs
|
|
|
|
.iter()
|
2025-04-16 12:16:40 +02:00
|
|
|
.filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None })
|
|
|
|
.max();
|
2025-02-09 22:49:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:23:11 +00:00
|
|
|
let Some(Ident { name, .. }) = attr.ident() else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
match name {
|
2023-03-19 10:00:27 +00:00
|
|
|
sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
|
|
|
|
sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR,
|
|
|
|
sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
|
|
|
|
sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST,
|
|
|
|
sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND,
|
|
|
|
sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR,
|
|
|
|
sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR,
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::rustc_allocator_zeroed => {
|
2023-03-19 10:00:27 +00:00
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
2023-03-19 10:00:27 +00:00
|
|
|
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
2023-03-19 10:04:44 +00:00
|
|
|
sym::no_mangle => {
|
|
|
|
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
2024-10-09 14:24:15 +02:00
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
|
|
|
mixed_export_name_no_mangle_lint_state.track_no_mangle(
|
2025-02-09 22:49:28 +01:00
|
|
|
attr.span(),
|
2024-10-09 14:24:15 +02:00
|
|
|
tcx.local_def_id_to_hir_id(did),
|
2024-12-09 20:23:02 +01:00
|
|
|
attr,
|
2024-10-09 14:24:15 +02:00
|
|
|
);
|
2023-03-19 10:04:44 +00:00
|
|
|
} else {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx()
|
2023-03-19 10:04:44 +00:00
|
|
|
.struct_span_err(
|
2025-02-09 22:49:28 +01:00
|
|
|
attr.span(),
|
2023-03-19 10:04:44 +00:00
|
|
|
format!(
|
|
|
|
"`#[no_mangle]` cannot be used on {} {} as it has no name",
|
|
|
|
tcx.def_descr_article(did.to_def_id()),
|
|
|
|
tcx.def_descr(did.to_def_id()),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::rustc_std_internal_symbol => {
|
2023-03-19 10:00:27 +00:00
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
|
|
|
sym::used => {
|
|
|
|
let inner = attr.meta_item_list();
|
|
|
|
match inner.as_deref() {
|
|
|
|
Some([item]) if item.has_name(sym::linker) => {
|
2024-10-09 09:01:57 +02:00
|
|
|
if !tcx.features().used_with_arg() {
|
2023-03-13 19:23:11 +00:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&tcx.sess,
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::used_with_arg,
|
2025-02-09 22:49:28 +01:00
|
|
|
attr.span(),
|
2023-03-13 19:23:11 +00:00
|
|
|
"`#[used(linker)]` is currently unstable",
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
Some([item]) if item.has_name(sym::compiler) => {
|
2024-10-09 09:01:57 +02:00
|
|
|
if !tcx.features().used_with_arg() {
|
2023-03-13 19:23:11 +00:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&tcx.sess,
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::used_with_arg,
|
2025-02-09 22:49:28 +01:00
|
|
|
attr.span(),
|
2023-03-13 19:23:11 +00:00
|
|
|
"`#[used(compiler)]` is currently unstable",
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
|
|
|
|
}
|
|
|
|
Some(_) => {
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// Unfortunately, unconditionally using `llvm.used` causes
|
|
|
|
// issues in handling `.init_array` with the gold linker,
|
2023-04-09 17:35:02 -04:00
|
|
|
// but using `llvm.compiler.used` caused a nontrivial amount
|
2023-03-13 19:23:11 +00:00
|
|
|
// of unintentional ecosystem breakage -- particularly on
|
|
|
|
// Mach-O targets.
|
|
|
|
//
|
|
|
|
// As a result, we emit `llvm.compiler.used` only on ELF
|
|
|
|
// targets. This is somewhat ad-hoc, but actually follows
|
|
|
|
// our pre-LLVM 13 behavior (prior to the ecosystem
|
|
|
|
// breakage), and seems to match `clang`'s behavior as well
|
|
|
|
// (both before and after LLVM 13), possibly because they
|
|
|
|
// have similar compatibility concerns to us. See
|
|
|
|
// https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
|
|
|
|
// and following comments for some discussion of this, as
|
|
|
|
// well as the comments in `rustc_codegen_llvm` where these
|
|
|
|
// flags are handled.
|
|
|
|
//
|
|
|
|
// Anyway, to be clear: this is still up in the air
|
|
|
|
// somewhat, and is subject to change in the future (which
|
|
|
|
// is a good thing, because this would ideally be a bit
|
|
|
|
// more firmed up).
|
2024-08-19 15:20:02 +02:00
|
|
|
let is_like_elf = !(tcx.sess.target.is_like_darwin
|
2023-03-13 19:23:11 +00:00
|
|
|
|| tcx.sess.target.is_like_windows
|
|
|
|
|| tcx.sess.target.is_like_wasm);
|
|
|
|
codegen_fn_attrs.flags |= if is_like_elf {
|
|
|
|
CodegenFnAttrFlags::USED
|
|
|
|
} else {
|
|
|
|
CodegenFnAttrFlags::USED_LINKER
|
|
|
|
};
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-19 10:00:27 +00:00
|
|
|
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::track_caller => {
|
2024-02-11 21:36:12 +00:00
|
|
|
let is_closure = tcx.is_closure_like(did.to_def_id());
|
2023-05-30 14:32:29 -07:00
|
|
|
|
|
|
|
if !is_closure
|
2023-03-13 19:35:24 +00:00
|
|
|
&& let Some(fn_sig) = fn_sig()
|
2025-02-05 12:22:28 -08:00
|
|
|
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
|
2023-03-13 19:35:24 +00:00
|
|
|
{
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() });
|
2023-03-13 19:35:24 +00:00
|
|
|
}
|
2023-05-30 14:32:29 -07:00
|
|
|
if is_closure
|
2024-10-09 09:01:57 +02:00
|
|
|
&& !tcx.features().closure_track_caller()
|
2025-02-09 22:49:28 +01:00
|
|
|
&& !attr.span().allows_unstable(sym::closure_track_caller)
|
2023-05-30 14:32:29 -07:00
|
|
|
{
|
2023-03-13 19:23:11 +00:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&tcx.sess,
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::closure_track_caller,
|
2025-02-09 22:49:28 +01:00
|
|
|
attr.span(),
|
2023-03-13 19:23:11 +00:00
|
|
|
"`#[track_caller]` on closures is currently unstable",
|
2022-12-08 03:53:35 +00:00
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
2023-03-19 10:00:27 +00:00
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::export_name => {
|
|
|
|
if let Some(s) = attr.value_str() {
|
|
|
|
if s.as_str().contains('\0') {
|
|
|
|
// `#[export_name = ...]` will be converted to a null-terminated string,
|
|
|
|
// so it may not contain any null characters.
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() });
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
|
|
|
codegen_fn_attrs.export_name = Some(s);
|
2025-02-09 22:49:28 +01:00
|
|
|
mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::target_feature => {
|
2024-12-13 12:19:46 +00:00
|
|
|
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn");
|
2024-12-13 12:19:46 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let safe_target_features =
|
|
|
|
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
|
|
|
|
codegen_fn_attrs.safe_target_features = safe_target_features;
|
|
|
|
if safe_target_features {
|
2023-03-13 19:23:11 +00:00
|
|
|
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
|
|
|
// The `#[target_feature]` attribute is allowed on
|
2023-09-23 22:51:43 -04:00
|
|
|
// WebAssembly targets on all functions. Prior to stabilizing
|
|
|
|
// the `target_feature_11` feature, `#[target_feature]` was
|
|
|
|
// only permitted on unsafe functions because on most targets
|
2023-03-13 19:23:11 +00:00
|
|
|
// execution of instructions that are not supported is
|
|
|
|
// considered undefined behavior. For WebAssembly which is a
|
|
|
|
// 100% safe target at execution time it's not possible to
|
|
|
|
// execute undefined instructions, and even if a future
|
|
|
|
// feature was added in some form for this it would be a
|
|
|
|
// deterministic trap. There is no undefined behavior when
|
|
|
|
// executing WebAssembly so `#[target_feature]` is allowed
|
|
|
|
// on safe functions (but again, only for WebAssembly)
|
|
|
|
//
|
|
|
|
// Note that this is also allowed if `actually_rustdoc` so
|
|
|
|
// if a target is documenting some wasm-specific code then
|
|
|
|
// it's not spuriously denied.
|
|
|
|
//
|
2023-09-23 22:51:43 -04:00
|
|
|
// Now that `#[target_feature]` is permitted on safe functions,
|
|
|
|
// this exception must still exist for allowing the attribute on
|
|
|
|
// `main`, `start`, and other functions that are not usually
|
|
|
|
// allowed.
|
2023-03-13 19:23:11 +00:00
|
|
|
} else {
|
2025-02-09 22:49:28 +01:00
|
|
|
check_target_feature_trait_unsafe(tcx, did, attr.span());
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
2024-09-02 11:45:59 +02:00
|
|
|
from_target_feature_attr(
|
2023-03-13 19:23:11 +00:00
|
|
|
tcx,
|
|
|
|
attr,
|
2024-09-02 11:45:59 +02:00
|
|
|
rust_target_features,
|
2023-03-13 19:23:11 +00:00
|
|
|
&mut codegen_fn_attrs.target_features,
|
|
|
|
);
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::linkage => {
|
|
|
|
if let Some(val) = attr.value_str() {
|
|
|
|
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
|
|
|
|
if tcx.is_foreign_item(did) {
|
|
|
|
codegen_fn_attrs.import_linkage = linkage;
|
2024-06-03 10:45:16 +00:00
|
|
|
|
|
|
|
if tcx.is_mutable_static(did.into()) {
|
|
|
|
let mut diag = tcx.dcx().struct_span_err(
|
2025-02-09 22:49:28 +01:00
|
|
|
attr.span(),
|
2024-06-03 10:45:16 +00:00
|
|
|
"extern mutable statics are not allowed with `#[linkage]`",
|
|
|
|
);
|
|
|
|
diag.note(
|
2024-09-11 09:59:50 +10:00
|
|
|
"marking the extern static mutable would allow changing which \
|
|
|
|
symbol the static references rather than make the target of the \
|
|
|
|
symbol mutable",
|
2024-06-03 10:45:16 +00:00
|
|
|
);
|
|
|
|
diag.emit();
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
} else {
|
|
|
|
codegen_fn_attrs.linkage = linkage;
|
|
|
|
}
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::link_section => {
|
|
|
|
if let Some(val) = attr.value_str() {
|
|
|
|
if val.as_str().bytes().any(|b| b == 0) {
|
2024-07-19 11:51:21 -04:00
|
|
|
let msg = format!("illegal null byte in link_section value: `{val}`");
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().span_err(attr.span(), msg);
|
2022-12-08 03:53:35 +00:00
|
|
|
} else {
|
2023-03-13 19:23:11 +00:00
|
|
|
codegen_fn_attrs.link_section = Some(val);
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-19 10:00:27 +00:00
|
|
|
sym::link_name => codegen_fn_attrs.link_name = attr.value_str(),
|
2023-03-13 19:23:11 +00:00
|
|
|
sym::link_ordinal => {
|
2025-02-09 22:49:28 +01:00
|
|
|
link_ordinal_span = Some(attr.span());
|
2023-03-13 19:23:11 +00:00
|
|
|
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
|
|
|
|
codegen_fn_attrs.link_ordinal = ordinal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sym::no_sanitize => {
|
2025-02-09 22:49:28 +01:00
|
|
|
no_sanitize_span = Some(attr.span());
|
2023-03-13 19:23:11 +00:00
|
|
|
if let Some(list) = attr.meta_item_list() {
|
|
|
|
for item in list.iter() {
|
2023-03-19 10:00:27 +00:00
|
|
|
match item.name_or_empty() {
|
|
|
|
sym::address => {
|
2023-03-13 19:35:24 +00:00
|
|
|
codegen_fn_attrs.no_sanitize |=
|
2023-03-19 10:00:27 +00:00
|
|
|
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
|
2023-03-13 19:35:24 +00:00
|
|
|
}
|
2023-03-19 10:00:27 +00:00
|
|
|
sym::cfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
|
|
|
|
sym::kcfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
|
|
|
|
sym::memory => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY,
|
|
|
|
sym::memtag => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG,
|
|
|
|
sym::shadow_call_stack => {
|
|
|
|
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK
|
2023-03-13 19:35:24 +00:00
|
|
|
}
|
2023-03-19 10:00:27 +00:00
|
|
|
sym::thread => codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD,
|
|
|
|
sym::hwaddress => {
|
|
|
|
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
|
2023-03-13 19:35:24 +00:00
|
|
|
}
|
|
|
|
_ => {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-01 20:26:05 +04:00
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
|
|
|
sym::instruction_set => {
|
|
|
|
codegen_fn_attrs.instruction_set =
|
|
|
|
attr.meta_item_list().and_then(|l| match &l[..] {
|
2024-10-04 21:59:04 +09:00
|
|
|
[MetaItemInner::MetaItem(set)] => {
|
2023-03-13 19:23:11 +00:00
|
|
|
let segments =
|
|
|
|
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
|
|
|
match segments.as_slice() {
|
2025-02-02 13:09:03 +00:00
|
|
|
[sym::arm, sym::a32 | sym::t32]
|
|
|
|
if !tcx.sess.target.has_thumb_interworking =>
|
|
|
|
{
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::UnsuportedInstructionSet {
|
|
|
|
span: attr.span(),
|
|
|
|
});
|
2025-02-02 13:09:03 +00:00
|
|
|
None
|
2023-03-13 19:23:11 +00:00
|
|
|
}
|
2025-02-02 13:09:03 +00:00
|
|
|
[sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
|
|
|
|
[sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
|
2023-03-13 19:23:11 +00:00
|
|
|
_ => {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::InvalidInstructionSet {
|
|
|
|
span: attr.span(),
|
|
|
|
});
|
2022-12-08 03:53:35 +00:00
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
[] => {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
|
2023-03-13 19:23:11 +00:00
|
|
|
None
|
|
|
|
}
|
2023-02-01 20:26:05 +04:00
|
|
|
_ => {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx()
|
|
|
|
.emit_err(errors::MultipleInstructionSet { span: attr.span() });
|
2023-02-01 20:26:05 +04:00
|
|
|
None
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
})
|
|
|
|
}
|
2023-12-12 13:37:04 -08:00
|
|
|
sym::patchable_function_entry => {
|
|
|
|
codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
|
2024-05-02 23:19:02 +02:00
|
|
|
let mut prefix = None;
|
|
|
|
let mut entry = None;
|
2023-12-12 13:37:04 -08:00
|
|
|
for item in l {
|
2024-05-02 23:19:02 +02:00
|
|
|
let Some(meta_item) = item.meta_item() else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
2024-05-02 23:19:02 +02:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let Some(name_value_lit) = meta_item.name_value_literal() else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
2024-05-02 23:19:02 +02:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let attrib_to_write = match meta_item.name_or_empty() {
|
|
|
|
sym::prefix_nops => &mut prefix,
|
|
|
|
sym::entry_nops => &mut entry,
|
|
|
|
_ => {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::UnexpectedParameterName {
|
|
|
|
span: item.span(),
|
|
|
|
prefix_nops: sym::prefix_nops,
|
|
|
|
entry_nops: sym::entry_nops,
|
|
|
|
});
|
2024-05-02 23:19:02 +02:00
|
|
|
continue;
|
2023-12-12 13:37:04 -08:00
|
|
|
}
|
2024-05-02 23:19:02 +02:00
|
|
|
};
|
|
|
|
|
2024-06-26 19:11:25 +02:00
|
|
|
let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::InvalidLiteralValue {
|
|
|
|
span: name_value_lit.span,
|
|
|
|
});
|
2024-06-26 19:11:25 +02:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let Ok(val) = val.get().try_into() else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx()
|
|
|
|
.emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
|
2024-05-02 23:19:02 +02:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2024-06-26 19:11:25 +02:00
|
|
|
*attrib_to_write = Some(val);
|
2023-12-12 13:37:04 -08:00
|
|
|
}
|
2024-05-02 23:19:02 +02:00
|
|
|
|
|
|
|
if let (None, None) = (prefix, entry) {
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
|
2024-05-02 23:19:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Some(PatchableFunctionEntry::from_prefix_and_entry(
|
|
|
|
prefix.unwrap_or(0),
|
|
|
|
entry.unwrap_or(0),
|
|
|
|
))
|
2023-12-12 13:37:04 -08:00
|
|
|
})
|
|
|
|
}
|
2023-03-13 19:23:11 +00:00
|
|
|
_ => {}
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-09 14:24:15 +02:00
|
|
|
mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
|
|
|
|
|
2022-12-08 03:53:35 +00:00
|
|
|
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
2024-12-10 12:05:24 +00:00
|
|
|
if !attr.has_name(sym::inline) {
|
|
|
|
return ia;
|
|
|
|
}
|
2022-12-08 03:53:35 +00:00
|
|
|
|
2024-12-10 12:05:24 +00:00
|
|
|
if attr.is_word() {
|
2025-02-02 13:09:03 +00:00
|
|
|
return InlineAttr::Hint;
|
|
|
|
}
|
|
|
|
let Some(ref items) = attr.meta_item_list() else {
|
|
|
|
return ia;
|
|
|
|
};
|
2025-02-09 22:49:28 +01:00
|
|
|
inline_span = Some(attr.span());
|
2024-12-10 12:05:24 +00:00
|
|
|
|
2025-02-02 13:09:03 +00:00
|
|
|
let [item] = &items[..] else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::ExpectedOneArgument { span: attr.span() });
|
2025-02-02 13:09:03 +00:00
|
|
|
return InlineAttr::None;
|
|
|
|
};
|
2025-02-09 22:49:28 +01:00
|
|
|
|
2025-02-02 13:09:03 +00:00
|
|
|
if item.has_name(sym::always) {
|
|
|
|
InlineAttr::Always
|
|
|
|
} else if item.has_name(sym::never) {
|
|
|
|
InlineAttr::Never
|
2024-10-17 01:14:01 +02:00
|
|
|
} else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::InvalidArgument { span: items[0].span() });
|
2025-02-02 13:09:03 +00:00
|
|
|
|
|
|
|
InlineAttr::None
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
});
|
2024-12-10 12:05:24 +00:00
|
|
|
codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| {
|
|
|
|
if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() {
|
|
|
|
return ia;
|
|
|
|
}
|
|
|
|
|
|
|
|
if attr.is_word() {
|
2025-02-09 22:49:28 +01:00
|
|
|
InlineAttr::Force { attr_span: attr.span(), reason: None }
|
2024-12-10 12:05:24 +00:00
|
|
|
} else if let Some(val) = attr.value_str() {
|
2025-02-09 22:49:28 +01:00
|
|
|
InlineAttr::Force { attr_span: attr.span(), reason: Some(val) }
|
2024-12-10 12:05:24 +00:00
|
|
|
} else {
|
|
|
|
debug!("`rustc_force_inline` not checked by attribute validation");
|
|
|
|
ia
|
|
|
|
}
|
|
|
|
});
|
2022-12-08 03:53:35 +00:00
|
|
|
|
2024-08-08 10:20:40 +02:00
|
|
|
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
|
|
|
|
// but not for the code generation backend because at that point the naked function will just be
|
|
|
|
// a declaration, with a definition provided in global assembly.
|
|
|
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
|
|
|
codegen_fn_attrs.inline = InlineAttr::Never;
|
|
|
|
}
|
|
|
|
|
2025-01-24 19:34:01 +00:00
|
|
|
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::Default, |ia, attr| {
|
2022-12-08 03:53:35 +00:00
|
|
|
if !attr.has_name(sym::optimize) {
|
|
|
|
return ia;
|
|
|
|
}
|
2024-10-17 01:14:01 +02:00
|
|
|
if attr.is_word() {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
|
2025-02-02 13:09:03 +00:00
|
|
|
return ia;
|
|
|
|
}
|
|
|
|
let Some(ref items) = attr.meta_item_list() else {
|
|
|
|
return OptimizeAttr::Default;
|
|
|
|
};
|
|
|
|
|
2025-02-09 22:49:28 +01:00
|
|
|
inline_span = Some(attr.span());
|
2025-02-02 13:09:03 +00:00
|
|
|
let [item] = &items[..] else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
|
2025-02-02 13:09:03 +00:00
|
|
|
return OptimizeAttr::Default;
|
|
|
|
};
|
|
|
|
if item.has_name(sym::size) {
|
|
|
|
OptimizeAttr::Size
|
|
|
|
} else if item.has_name(sym::speed) {
|
|
|
|
OptimizeAttr::Speed
|
|
|
|
} else if item.has_name(sym::none) {
|
|
|
|
OptimizeAttr::DoNotOptimize
|
2024-10-17 01:14:01 +02:00
|
|
|
} else {
|
2025-02-19 16:47:28 +00:00
|
|
|
tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() });
|
2025-01-24 19:34:01 +00:00
|
|
|
OptimizeAttr::Default
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// #73631: closures inherit `#[target_feature]` annotations
|
2023-05-21 21:51:57 -04:00
|
|
|
//
|
|
|
|
// If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`.
|
|
|
|
//
|
|
|
|
// At this point, `unsafe` has already been checked and `#[target_feature]` only affects codegen.
|
2024-11-23 16:42:20 +01:00
|
|
|
// Due to LLVM limitations, emitting both `#[inline(always)]` and `#[target_feature]` is *unsound*:
|
|
|
|
// the function may be inlined into a caller with fewer target features. Also see
|
|
|
|
// <https://github.com/rust-lang/rust/issues/116573>.
|
2023-05-21 21:51:57 -04:00
|
|
|
//
|
|
|
|
// Using `#[inline(always)]` implies that this closure will most likely be inlined into
|
|
|
|
// its parent function, which effectively inherits the features anyway. Boxing this closure
|
|
|
|
// would result in this closure being compiled without the inherited target features, but this
|
|
|
|
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
|
2023-09-23 22:51:43 -04:00
|
|
|
if tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always {
|
2022-12-08 03:53:35 +00:00
|
|
|
let owner_id = tcx.parent(did.to_def_id());
|
|
|
|
if tcx.def_kind(owner_id).has_codegen_attrs() {
|
|
|
|
codegen_fn_attrs
|
|
|
|
.target_features
|
|
|
|
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-23 18:46:23 +01:00
|
|
|
// If a function uses `#[target_feature]` it can't be inlined into general
|
2022-12-08 03:53:35 +00:00
|
|
|
// purpose functions as they wouldn't have the right target features
|
2024-09-23 18:46:23 +01:00
|
|
|
// enabled. For that reason we also forbid `#[inline(always)]` as it can't be
|
2022-12-08 03:53:35 +00:00
|
|
|
// respected.
|
2024-09-23 18:46:23 +01:00
|
|
|
//
|
2024-12-18 13:54:41 +00:00
|
|
|
// `#[rustc_force_inline]` doesn't need to be prohibited here, only
|
|
|
|
// `#[inline(always)]`, as forced inlining is implemented entirely within
|
|
|
|
// rustc (and so the MIR inliner can do any necessary checks for compatible target
|
|
|
|
// features).
|
|
|
|
//
|
|
|
|
// This sidesteps the LLVM blockers in enabling `target_features` +
|
|
|
|
// `inline(always)` to be used together (see rust-lang/rust#116573 and
|
|
|
|
// llvm/llvm-project#70563).
|
2024-09-23 18:46:23 +01:00
|
|
|
if !codegen_fn_attrs.target_features.is_empty()
|
|
|
|
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
|
2025-02-02 13:04:38 +00:00
|
|
|
&& let Some(span) = inline_span
|
2024-09-11 13:32:53 -04:00
|
|
|
{
|
2025-02-02 13:04:38 +00:00
|
|
|
tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
|
2025-02-02 13:04:38 +00:00
|
|
|
if !codegen_fn_attrs.no_sanitize.is_empty()
|
|
|
|
&& codegen_fn_attrs.inline.always()
|
|
|
|
&& let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span)
|
|
|
|
{
|
|
|
|
let hir_id = tcx.local_def_id_to_hir_id(did);
|
|
|
|
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
|
|
|
|
lint.primary_message("`no_sanitize` will have no effect after inlining");
|
|
|
|
lint.span_note(inline_span, "inlining requested here");
|
|
|
|
})
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Weak lang items have the same semantics as "std internal" symbols in the
|
|
|
|
// sense that they're preserved through all our LTO passes and only
|
|
|
|
// strippable by the linker.
|
|
|
|
//
|
|
|
|
// Additionally weak lang items have predetermined symbol names.
|
|
|
|
if let Some((name, _)) = lang_items::extract(attrs)
|
|
|
|
&& let Some(lang_item) = LangItem::from_name(name)
|
|
|
|
{
|
2025-03-28 12:21:21 +00:00
|
|
|
if WEAK_LANG_ITEMS.contains(&lang_item) {
|
2023-12-02 14:17:33 +00:00
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
|
|
|
}
|
|
|
|
if let Some(link_name) = lang_item.link_name() {
|
|
|
|
codegen_fn_attrs.export_name = Some(link_name);
|
|
|
|
codegen_fn_attrs.link_name = Some(link_name);
|
|
|
|
}
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
|
|
|
|
|
|
|
|
// Any linkage to LLVM intrinsics for now forcibly marks them all as never
|
|
|
|
// unwinds since LLVM sometimes can't handle codegen which `invoke`s
|
|
|
|
// intrinsic functions.
|
2025-02-02 13:04:38 +00:00
|
|
|
if let Some(name) = &codegen_fn_attrs.link_name
|
|
|
|
&& name.as_str().starts_with("llvm.")
|
|
|
|
{
|
|
|
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
|
2024-09-11 13:57:12 +01:00
|
|
|
if let Some(features) = check_tied_features(
|
|
|
|
tcx.sess,
|
|
|
|
&codegen_fn_attrs
|
|
|
|
.target_features
|
|
|
|
.iter()
|
|
|
|
.map(|features| (features.name.as_str(), true))
|
|
|
|
.collect(),
|
|
|
|
) {
|
|
|
|
let span = tcx
|
|
|
|
.get_attrs(did, sym::target_feature)
|
|
|
|
.next()
|
2025-02-09 22:49:28 +01:00
|
|
|
.map_or_else(|| tcx.def_span(did), |a| a.span());
|
2024-09-11 13:57:12 +01:00
|
|
|
tcx.dcx()
|
2024-09-02 11:45:59 +02:00
|
|
|
.create_err(errors::TargetFeatureDisableOrEnable {
|
2024-09-11 13:57:12 +01:00
|
|
|
features,
|
|
|
|
span: Some(span),
|
2024-09-02 11:45:59 +02:00
|
|
|
missing_features: Some(errors::MissingFeatures),
|
2024-09-11 13:57:12 +01:00
|
|
|
})
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
|
2022-12-08 03:53:35 +00:00
|
|
|
codegen_fn_attrs
|
|
|
|
}
|
|
|
|
|
2024-09-11 13:57:12 +01:00
|
|
|
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
|
|
|
|
/// combinations are allowed.
|
|
|
|
pub fn check_tied_features(
|
|
|
|
sess: &Session,
|
|
|
|
features: &FxHashMap<&str, bool>,
|
|
|
|
) -> Option<&'static [&'static str]> {
|
|
|
|
if !features.is_empty() {
|
|
|
|
for tied in sess.target.tied_target_features() {
|
|
|
|
// Tied features must be set to the same value, or not set at all
|
|
|
|
let mut tied_iter = tied.iter();
|
|
|
|
let enabled = features.get(tied_iter.next().unwrap());
|
|
|
|
if tied_iter.any(|f| enabled != features.get(f)) {
|
|
|
|
return Some(tied);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2022-12-08 03:53:35 +00:00
|
|
|
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
|
|
|
|
/// applied to the method prototype.
|
|
|
|
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|
|
|
if let Some(impl_item) = tcx.opt_associated_item(def_id)
|
2024-11-03 21:47:56 +00:00
|
|
|
&& let ty::AssocItemContainer::Impl = impl_item.container
|
2022-12-08 03:53:35 +00:00
|
|
|
&& let Some(trait_item) = impl_item.trait_item_def_id
|
|
|
|
{
|
|
|
|
return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER);
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2024-10-17 01:14:01 +02:00
|
|
|
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
|
2022-12-08 03:53:35 +00:00
|
|
|
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
|
2025-02-02 13:09:03 +00:00
|
|
|
let meta_item_list = attr.meta_item_list()?;
|
|
|
|
let [sole_meta_list] = &meta_item_list[..] else {
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span() });
|
2025-02-02 13:09:03 +00:00
|
|
|
return None;
|
2022-12-08 03:53:35 +00:00
|
|
|
};
|
|
|
|
if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
|
2025-02-02 13:09:03 +00:00
|
|
|
sole_meta_list.lit()
|
2022-12-08 03:53:35 +00:00
|
|
|
{
|
2024-09-11 09:59:50 +10:00
|
|
|
// According to the table at
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the
|
|
|
|
// ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
|
|
|
|
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import
|
|
|
|
// information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
|
2022-12-08 03:53:35 +00:00
|
|
|
//
|
2024-09-11 09:59:50 +10:00
|
|
|
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for
|
|
|
|
// this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that
|
|
|
|
// specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import
|
|
|
|
// library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an
|
|
|
|
// import library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I
|
|
|
|
// don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL --
|
|
|
|
// see earlier comment about LINK.EXE failing.)
|
2022-12-08 03:53:35 +00:00
|
|
|
if *ordinal <= u16::MAX as u128 {
|
2024-01-17 15:40:30 -08:00
|
|
|
Some(ordinal.get() as u16)
|
2022-12-08 03:53:35 +00:00
|
|
|
} else {
|
2024-07-19 11:51:21 -04:00
|
|
|
let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`");
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx()
|
2025-02-09 22:49:28 +01:00
|
|
|
.struct_span_err(attr.span(), msg)
|
2024-01-09 09:08:49 +11:00
|
|
|
.with_note("the value may not exceed `u16::MAX`")
|
2022-12-08 03:53:35 +00:00
|
|
|
.emit();
|
|
|
|
None
|
|
|
|
}
|
|
|
|
} else {
|
2025-02-09 22:49:28 +01:00
|
|
|
tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span() });
|
2022-12-08 03:53:35 +00:00
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_link_name_xor_ordinal(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
codegen_fn_attrs: &CodegenFnAttrs,
|
|
|
|
inline_span: Option<Span>,
|
|
|
|
) {
|
|
|
|
if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
|
|
|
|
if let Some(span) = inline_span {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().span_err(span, msg);
|
2022-12-08 03:53:35 +00:00
|
|
|
} else {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().err(msg);
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-09 14:24:15 +02:00
|
|
|
#[derive(Default)]
|
2024-12-09 20:23:02 +01:00
|
|
|
struct MixedExportNameAndNoMangleState<'a> {
|
2024-10-09 14:24:15 +02:00
|
|
|
export_name: Option<Span>,
|
|
|
|
hir_id: Option<HirId>,
|
|
|
|
no_mangle: Option<Span>,
|
2024-10-17 01:14:01 +02:00
|
|
|
no_mangle_attr: Option<&'a hir::Attribute>,
|
2024-10-09 14:24:15 +02:00
|
|
|
}
|
|
|
|
|
2024-12-09 20:23:02 +01:00
|
|
|
impl<'a> MixedExportNameAndNoMangleState<'a> {
|
2024-10-09 14:24:15 +02:00
|
|
|
fn track_export_name(&mut self, span: Span) {
|
|
|
|
self.export_name = Some(span);
|
|
|
|
}
|
|
|
|
|
2024-10-17 01:14:01 +02:00
|
|
|
fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) {
|
2024-10-09 14:24:15 +02:00
|
|
|
self.no_mangle = Some(span);
|
|
|
|
self.hir_id = Some(hir_id);
|
2024-12-09 20:23:02 +01:00
|
|
|
self.no_mangle_attr = Some(attr_name);
|
2024-10-09 14:24:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit diagnostics if the lint condition is met.
|
|
|
|
fn lint_if_mixed(self, tcx: TyCtxt<'_>) {
|
|
|
|
if let Self {
|
|
|
|
export_name: Some(export_name),
|
|
|
|
no_mangle: Some(no_mangle),
|
|
|
|
hir_id: Some(hir_id),
|
2025-02-09 22:49:33 +01:00
|
|
|
no_mangle_attr: Some(_),
|
2024-10-09 14:24:15 +02:00
|
|
|
} = self
|
|
|
|
{
|
|
|
|
tcx.emit_node_span_lint(
|
|
|
|
lint::builtin::UNUSED_ATTRIBUTES,
|
|
|
|
hir_id,
|
|
|
|
no_mangle,
|
|
|
|
errors::MixedExportNameAndNoMangle {
|
|
|
|
no_mangle,
|
2025-02-09 22:49:33 +01:00
|
|
|
no_mangle_attr: "#[unsafe(no_mangle)]".to_string(),
|
2024-10-09 14:24:15 +02:00
|
|
|
export_name,
|
|
|
|
removal_span: no_mangle,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-29 21:31:13 -05:00
|
|
|
/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
|
|
|
|
/// macros. There are two forms. The pure one without args to mark primal functions (the functions
|
|
|
|
/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the
|
|
|
|
/// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never
|
|
|
|
/// panic, unless we introduced a bug when parsing the autodiff macro.
|
|
|
|
fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
|
|
|
|
let attrs = tcx.get_attrs(id, sym::rustc_autodiff);
|
|
|
|
|
|
|
|
let attrs =
|
|
|
|
attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::<Vec<_>>();
|
|
|
|
|
|
|
|
// check for exactly one autodiff attribute on placeholder functions.
|
|
|
|
// There should only be one, since we generate a new placeholder per ad macro.
|
|
|
|
let attr = match &attrs[..] {
|
|
|
|
[] => return None,
|
|
|
|
[attr] => attr,
|
|
|
|
_ => {
|
2025-02-09 22:49:31 +01:00
|
|
|
span_bug!(attrs[1].span(), "cg_ssa: rustc_autodiff should only exist once per source");
|
2025-01-29 21:31:13 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let list = attr.meta_item_list().unwrap_or_default();
|
|
|
|
|
|
|
|
// empty autodiff attribute macros (i.e. `#[autodiff]`) are used to mark source functions
|
|
|
|
if list.is_empty() {
|
|
|
|
return Some(AutoDiffAttrs::source());
|
|
|
|
}
|
|
|
|
|
2025-04-03 17:21:21 -04:00
|
|
|
let [mode, width_meta, input_activities @ .., ret_activity] = &list[..] else {
|
|
|
|
span_bug!(attr.span(), "rustc_autodiff attribute must contain mode, width and activities");
|
2025-01-29 21:31:13 -05:00
|
|
|
};
|
2025-02-20 18:28:48 +00:00
|
|
|
let mode = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = mode {
|
2025-01-29 21:31:13 -05:00
|
|
|
p1.segments.first().unwrap().ident
|
|
|
|
} else {
|
2025-02-09 22:49:31 +01:00
|
|
|
span_bug!(attr.span(), "rustc_autodiff attribute must contain mode");
|
2025-01-29 21:31:13 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// parse mode
|
|
|
|
let mode = match mode.as_str() {
|
|
|
|
"Forward" => DiffMode::Forward,
|
|
|
|
"Reverse" => DiffMode::Reverse,
|
|
|
|
_ => {
|
|
|
|
span_bug!(mode.span, "rustc_autodiff attribute contains invalid mode");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2025-04-03 17:21:21 -04:00
|
|
|
let width: u32 = match width_meta {
|
|
|
|
MetaItemInner::MetaItem(MetaItem { path: p1, .. }) => {
|
|
|
|
let w = p1.segments.first().unwrap().ident;
|
|
|
|
match w.as_str().parse() {
|
|
|
|
Ok(val) => val,
|
|
|
|
Err(_) => {
|
|
|
|
span_bug!(w.span, "rustc_autodiff width should fit u32");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MetaItemInner::Lit(lit) => {
|
|
|
|
if let LitKind::Int(val, _) = lit.kind {
|
|
|
|
match val.get().try_into() {
|
|
|
|
Ok(val) => val,
|
|
|
|
Err(_) => {
|
|
|
|
span_bug!(lit.span, "rustc_autodiff width should fit u32");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
span_bug!(lit.span, "rustc_autodiff width should be an integer");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2025-01-29 21:31:13 -05:00
|
|
|
// First read the ret symbol from the attribute
|
2025-02-20 18:28:48 +00:00
|
|
|
let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity {
|
2025-01-29 21:31:13 -05:00
|
|
|
p1.segments.first().unwrap().ident
|
|
|
|
} else {
|
2025-02-09 22:49:31 +01:00
|
|
|
span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity");
|
2025-01-29 21:31:13 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// Then parse it into an actual DiffActivity
|
|
|
|
let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else {
|
|
|
|
span_bug!(ret_symbol.span, "invalid return activity");
|
|
|
|
};
|
|
|
|
|
|
|
|
// Now parse all the intermediate (input) activities
|
|
|
|
let mut arg_activities: Vec<DiffActivity> = vec![];
|
|
|
|
for arg in input_activities {
|
2025-02-20 18:28:48 +00:00
|
|
|
let arg_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p2, .. }) = arg {
|
2025-01-29 21:31:13 -05:00
|
|
|
match p2.segments.first() {
|
|
|
|
Some(x) => x.ident,
|
|
|
|
None => {
|
|
|
|
span_bug!(
|
|
|
|
arg.span(),
|
|
|
|
"rustc_autodiff attribute must contain the input activity"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
span_bug!(arg.span(), "rustc_autodiff attribute must contain the input activity");
|
|
|
|
};
|
|
|
|
|
|
|
|
match DiffActivity::from_str(arg_symbol.as_str()) {
|
|
|
|
Ok(arg_activity) => arg_activities.push(arg_activity),
|
|
|
|
Err(_) => {
|
|
|
|
span_bug!(arg_symbol.span, "invalid input activity");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-03 17:21:21 -04:00
|
|
|
Some(AutoDiffAttrs { mode, width, ret_activity, input_activity: arg_activities })
|
2025-01-29 21:31:13 -05:00
|
|
|
}
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) fn provide(providers: &mut Providers) {
|
2024-09-01 16:35:53 +02:00
|
|
|
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
|
2022-12-08 03:53:35 +00:00
|
|
|
}
|