rustc_middle/middle/
codegen_fn_attrs.rs

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