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