rustc_middle/middle/
codegen_fn_attrs.rs

1use std::borrow::Cow;
2
3use rustc_abi::Align;
4use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr};
5use rustc_hir::def_id::DefId;
6use rustc_macros::{HashStable, TyDecodable, TyEncodable};
7use rustc_span::Symbol;
8use rustc_target::spec::SanitizerSet;
9
10use crate::ty::{InstanceKind, TyCtxt};
11
12impl<'tcx> TyCtxt<'tcx> {
13    pub fn codegen_instance_attrs(
14        self,
15        instance_kind: InstanceKind<'_>,
16    ) -> Cow<'tcx, CodegenFnAttrs> {
17        let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id()));
18
19        // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that
20        // are generated for indirect function calls.
21        if !matches!(instance_kind, InstanceKind::Item(_)) {
22            if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
23                attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED);
24            }
25        }
26
27        attrs
28    }
29}
30
31#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
32pub struct CodegenFnAttrs {
33    pub flags: CodegenFnAttrFlags,
34    /// Parsed representation of the `#[inline]` attribute
35    pub inline: InlineAttr,
36    /// Parsed representation of the `#[optimize]` attribute
37    pub optimize: OptimizeAttr,
38    /// The name this function will be imported/exported under. This can be set
39    /// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
40    /// depending on if this is a function definition or foreign function.
41    pub symbol_name: Option<Symbol>,
42    /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
43    /// imported function has in the dynamic library. Note that this must not
44    /// be set when `link_name` is set. This is for foreign items with the
45    /// "raw-dylib" kind.
46    pub link_ordinal: Option<u16>,
47    /// The `#[target_feature(enable = "...")]` attribute and the enabled
48    /// features (only enabled features are supported right now).
49    /// Implied target features have already been applied.
50    pub target_features: Vec<TargetFeature>,
51    /// Whether the function was declared safe, but has target features
52    pub safe_target_features: bool,
53    /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
54    pub linkage: Option<Linkage>,
55    /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
56    pub import_linkage: Option<Linkage>,
57    /// The `#[link_section = "..."]` attribute, or what executable section this
58    /// should be placed in.
59    pub link_section: Option<Symbol>,
60    /// The `#[sanitize(xyz = "off")]` attribute. Indicates sanitizers for which
61    /// instrumentation should be disabled inside the function.
62    pub no_sanitize: SanitizerSet,
63    /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
64    /// be generated against a specific instruction set. Only usable on architectures which allow
65    /// switching between multiple instruction sets.
66    pub instruction_set: Option<InstructionSetAttr>,
67    /// The `#[align(...)]` attribute. Determines the alignment of the function body.
68    // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
69    pub alignment: Option<Align>,
70    /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
71    /// the function entry.
72    pub patchable_function_entry: Option<PatchableFunctionEntry>,
73}
74
75#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
76pub struct TargetFeature {
77    /// The name of the target feature (e.g. "avx")
78    pub name: Symbol,
79    /// The feature is implied by another feature, rather than explicitly added by the
80    /// `#[target_feature]` attribute
81    pub implied: bool,
82}
83
84#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
85pub struct PatchableFunctionEntry {
86    /// Nops to prepend to the function
87    prefix: u8,
88    /// Nops after entry, but before body
89    entry: u8,
90}
91
92impl PatchableFunctionEntry {
93    pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self {
94        Self { prefix: config.prefix(), entry: config.entry() }
95    }
96    pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self {
97        Self { prefix, entry }
98    }
99    pub fn prefix(&self) -> u8 {
100        self.prefix
101    }
102    pub fn entry(&self) -> u8 {
103        self.entry
104    }
105}
106
107#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
108pub struct CodegenFnAttrFlags(u32);
109bitflags::bitflags! {
110    impl CodegenFnAttrFlags: u32 {
111        /// `#[cold]`: a hint to LLVM that this function, when called, is never on
112        /// the hot path.
113        const COLD                      = 1 << 0;
114        /// `#[rustc_nounwind]`: An indicator that function will never unwind.
115        const NEVER_UNWIND              = 1 << 1;
116        /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue
117        /// should be generated.
118        const NAKED                     = 1 << 2;
119        /// `#[no_mangle]`: an indicator that the function's name should be the same
120        /// as its symbol.
121        const NO_MANGLE                 = 1 << 3;
122        /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a
123        /// "weird symbol" for the standard library in that it has slightly
124        /// different linkage, visibility, and reachability rules.
125        const RUSTC_STD_INTERNAL_SYMBOL = 1 << 4;
126        /// `#[thread_local]`: indicates a static is actually a thread local
127        /// piece of memory
128        const THREAD_LOCAL              = 1 << 5;
129        /// `#[used(compiler)]`: indicates that LLVM can't eliminate this function (but the
130        /// linker can!).
131        const USED_COMPILER             = 1 << 6;
132        /// `#[used(linker)]`:
133        /// indicates that neither LLVM nor the linker will eliminate this function.
134        const USED_LINKER               = 1 << 7;
135        /// `#[track_caller]`: allow access to the caller location
136        const TRACK_CALLER              = 1 << 8;
137        /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
138        /// declaration.
139        const FFI_PURE                  = 1 << 9;
140        /// #[ffi_const]: applies clang's `const` attribute to a foreign function
141        /// declaration.
142        const FFI_CONST                 = 1 << 10;
143        /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
144        /// function is never null and the function has no side effects other than allocating.
145        const ALLOCATOR                 = 1 << 11;
146        /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
147        const DEALLOCATOR               = 1 << 12;
148        /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
149        const REALLOCATOR               = 1 << 13;
150        /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
151        const ALLOCATOR_ZEROED          = 1 << 14;
152        /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
153        const NO_BUILTINS               = 1 << 15;
154    }
155}
156rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
157
158impl CodegenFnAttrs {
159    pub const EMPTY: &'static Self = &Self::new();
160
161    pub const fn new() -> CodegenFnAttrs {
162        CodegenFnAttrs {
163            flags: CodegenFnAttrFlags::empty(),
164            inline: InlineAttr::None,
165            optimize: OptimizeAttr::Default,
166            symbol_name: None,
167            link_ordinal: None,
168            target_features: vec![],
169            safe_target_features: false,
170            linkage: None,
171            import_linkage: None,
172            link_section: None,
173            no_sanitize: SanitizerSet::empty(),
174            instruction_set: None,
175            alignment: None,
176            patchable_function_entry: None,
177        }
178    }
179
180    /// Returns `true` if it looks like this symbol needs to be exported, for example:
181    ///
182    /// * `#[no_mangle]` is present
183    /// * `#[export_name(...)]` is present
184    /// * `#[linkage]` is present
185    ///
186    /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.
187    pub fn contains_extern_indicator(&self, tcx: TyCtxt<'_>, did: DefId) -> bool {
188        if tcx.is_foreign_item(did) {
189            return false;
190        }
191
192        self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
193            || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
194            || self.symbol_name.is_some()
195            || match self.linkage {
196                // These are private, so make sure we don't try to consider
197                // them external.
198                None | Some(Linkage::Internal) => false,
199                Some(_) => true,
200            }
201    }
202}