rustc_middle/middle/
codegen_fn_attrs.rs

1use std::borrow::Cow;
2
3use rustc_abi::Align;
4use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr, RtsanSetting};
5use rustc_macros::{HashStable, TyDecodable, TyEncodable};
6use rustc_span::Symbol;
7use rustc_target::spec::SanitizerSet;
8
9use crate::mir::mono::Visibility;
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        // NOTE: we try to not clone the `CodegenFnAttrs` when that is not needed.
18        // The `to_mut` method used below clones the inner value.
19        let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id()));
20
21        // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that
22        // are generated for indirect function calls.
23        if !matches!(instance_kind, InstanceKind::Item(_)) {
24            if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
25                attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED);
26            }
27        }
28
29        // A shim created by `#[track_caller]` should not inherit any attributes
30        // that modify the symbol name. Failing to remove these attributes from
31        // the shim leads to errors like `symbol `foo` is already defined`.
32        //
33        // A `ClosureOnceShim` with the track_caller attribute does not have a symbol,
34        // and therefore can be skipped here.
35        if let InstanceKind::ReifyShim(_, _) = instance_kind
36            && attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
37        {
38            if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
39                attrs.to_mut().flags.remove(CodegenFnAttrFlags::NO_MANGLE);
40            }
41
42            if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
43                attrs.to_mut().flags.remove(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
44            }
45
46            if attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM) {
47                attrs.to_mut().flags.remove(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM);
48            }
49
50            if attrs.symbol_name.is_some() {
51                attrs.to_mut().symbol_name = None;
52            }
53        }
54
55        attrs
56    }
57}
58
59#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
60pub struct CodegenFnAttrs {
61    pub flags: CodegenFnAttrFlags,
62    /// Parsed representation of the `#[inline]` attribute
63    pub inline: InlineAttr,
64    /// Parsed representation of the `#[optimize]` attribute
65    pub optimize: OptimizeAttr,
66    /// The name this function will be imported/exported under. This can be set
67    /// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
68    /// depending on if this is a function definition or foreign function.
69    pub symbol_name: Option<Symbol>,
70    /// Defids of foreign items somewhere that this function should "satisfy".
71    /// i.e., if a foreign function has some symbol foo,
72    /// generate this function under its real name,
73    /// but *also* under the same name as this foreign function so that the foreign function has an implementation.
74    // FIXME: make "SymbolName<'tcx>"
75    pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>,
76    /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
77    /// imported function has in the dynamic library. Note that this must not
78    /// be set when `link_name` is set. This is for foreign items with the
79    /// "raw-dylib" kind.
80    pub link_ordinal: Option<u16>,
81    /// The `#[target_feature(enable = "...")]` attribute and the enabled
82    /// features (only enabled features are supported right now).
83    /// Implied target features have already been applied.
84    pub target_features: Vec<TargetFeature>,
85    /// Whether the function was declared safe, but has target features
86    pub safe_target_features: bool,
87    /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
88    pub linkage: Option<Linkage>,
89    /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
90    pub import_linkage: Option<Linkage>,
91    /// The `#[link_section = "..."]` attribute, or what executable section this
92    /// should be placed in.
93    pub link_section: Option<Symbol>,
94    /// The `#[sanitize(xyz = "off")]` attribute. Indicates the settings for each
95    /// sanitizer for this function.
96    pub sanitizers: SanitizerFnAttrs,
97    /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
98    /// be generated against a specific instruction set. Only usable on architectures which allow
99    /// switching between multiple instruction sets.
100    pub instruction_set: Option<InstructionSetAttr>,
101    /// The `#[align(...)]` attribute. Determines the alignment of the function body.
102    // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
103    pub alignment: Option<Align>,
104    /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
105    /// the function entry.
106    pub patchable_function_entry: Option<PatchableFunctionEntry>,
107    /// The `#[rustc_objc_class = "..."]` attribute.
108    pub objc_class: Option<Symbol>,
109    /// The `#[rustc_objc_selector = "..."]` attribute.
110    pub objc_selector: Option<Symbol>,
111}
112
113#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)]
114pub enum TargetFeatureKind {
115    /// The feature is implied by another feature, rather than explicitly added by the
116    /// `#[target_feature]` attribute
117    Implied,
118    /// The feature is added by the regular `target_feature` attribute.
119    Enabled,
120    /// The feature is added by the unsafe `force_target_feature` attribute.
121    Forced,
122}
123
124#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)]
125pub struct TargetFeature {
126    /// The name of the target feature (e.g. "avx")
127    pub name: Symbol,
128    /// The way this feature was enabled.
129    pub kind: TargetFeatureKind,
130}
131
132#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
133pub struct PatchableFunctionEntry {
134    /// Nops to prepend to the function
135    prefix: u8,
136    /// Nops after entry, but before body
137    entry: u8,
138}
139
140impl PatchableFunctionEntry {
141    pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self {
142        Self { prefix: config.prefix(), entry: config.entry() }
143    }
144    pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self {
145        Self { prefix, entry }
146    }
147    pub fn prefix(&self) -> u8 {
148        self.prefix
149    }
150    pub fn entry(&self) -> u8 {
151        self.entry
152    }
153}
154
155#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
156pub struct CodegenFnAttrFlags(u32);
157bitflags::bitflags! {
158    impl CodegenFnAttrFlags: u32 {
159        /// `#[cold]`: a hint to LLVM that this function, when called, is never on
160        /// the hot path.
161        const COLD                      = 1 << 0;
162        /// `#[rustc_nounwind]`: An indicator that function will never unwind.
163        const NEVER_UNWIND              = 1 << 1;
164        /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue
165        /// should be generated.
166        const NAKED                     = 1 << 2;
167        /// `#[no_mangle]`: an indicator that the function's name should be the same
168        /// as its symbol.
169        const NO_MANGLE                 = 1 << 3;
170        /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a
171        /// "weird symbol" for the standard library in that it has slightly
172        /// different linkage, visibility, and reachability rules.
173        const RUSTC_STD_INTERNAL_SYMBOL = 1 << 4;
174        /// `#[thread_local]`: indicates a static is actually a thread local
175        /// piece of memory
176        const THREAD_LOCAL              = 1 << 5;
177        /// `#[used(compiler)]`: indicates that LLVM can't eliminate this function (but the
178        /// linker can!).
179        const USED_COMPILER             = 1 << 6;
180        /// `#[used(linker)]`:
181        /// indicates that neither LLVM nor the linker will eliminate this function.
182        const USED_LINKER               = 1 << 7;
183        /// `#[track_caller]`: allow access to the caller location
184        const TRACK_CALLER              = 1 << 8;
185        /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
186        /// declaration.
187        const FFI_PURE                  = 1 << 9;
188        /// #[ffi_const]: applies clang's `const` attribute to a foreign function
189        /// declaration.
190        const FFI_CONST                 = 1 << 10;
191        /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
192        /// function is never null and the function has no side effects other than allocating.
193        const ALLOCATOR                 = 1 << 11;
194        /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
195        const DEALLOCATOR               = 1 << 12;
196        /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
197        const REALLOCATOR               = 1 << 13;
198        /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
199        const ALLOCATOR_ZEROED          = 1 << 14;
200        /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
201        const NO_BUILTINS               = 1 << 15;
202        /// Marks foreign items, to make `contains_extern_indicator` cheaper.
203        const FOREIGN_ITEM              = 1 << 16;
204        /// `#[rustc_offload_kernel]`: indicates that this is an offload kernel, an extra ptr arg will be added.
205        const OFFLOAD_KERNEL = 1 << 17;
206        /// Externally implementable item symbols act a little like `RUSTC_STD_INTERNAL_SYMBOL`.
207        /// When a crate declares an EII and dependencies expect the symbol to exist,
208        /// they will refer to this symbol name before a definition is given.
209        /// As such, we must make sure these symbols really do exist in the final binary/library.
210        /// This flag is put on both the implementations of EIIs and the foreign item they implement.
211        const EXTERNALLY_IMPLEMENTABLE_ITEM = 1 << 18;
212    }
213}
214rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
215
216impl CodegenFnAttrs {
217    pub const EMPTY: &'static Self = &Self::new();
218
219    pub const fn new() -> CodegenFnAttrs {
220        CodegenFnAttrs {
221            flags: CodegenFnAttrFlags::empty(),
222            inline: InlineAttr::None,
223            optimize: OptimizeAttr::Default,
224            symbol_name: None,
225            link_ordinal: None,
226            target_features: vec![],
227            foreign_item_symbol_aliases: vec![],
228            safe_target_features: false,
229            linkage: None,
230            import_linkage: None,
231            link_section: None,
232            sanitizers: SanitizerFnAttrs::default(),
233            instruction_set: None,
234            alignment: None,
235            patchable_function_entry: None,
236            objc_class: None,
237            objc_selector: None,
238        }
239    }
240
241    /// Returns `true` if it looks like this symbol needs to be exported, for example:
242    ///
243    /// * `#[no_mangle]` is present
244    /// * `#[export_name(...)]` is present
245    /// * `#[linkage]` is present
246    ///
247    /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.
248    pub fn contains_extern_indicator(&self) -> bool {
249        if self.flags.contains(CodegenFnAttrFlags::FOREIGN_ITEM) {
250            return false;
251        }
252
253        self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
254            || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
255            // note: for these we do also set a symbol name so technically also handled by the
256            // condition below. However, I think that regardless these should be treated as extern.
257            || self.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM)
258            || self.symbol_name.is_some()
259            || match self.linkage {
260                // These are private, so make sure we don't try to consider
261                // them external.
262                None | Some(Linkage::Internal) => false,
263                Some(_) => true,
264            }
265    }
266}
267
268#[derive(Clone, Copy, Debug, HashStable, TyEncodable, TyDecodable, Eq, PartialEq)]
269pub struct SanitizerFnAttrs {
270    pub disabled: SanitizerSet,
271    pub rtsan_setting: RtsanSetting,
272}
273
274impl const Default for SanitizerFnAttrs {
275    fn default() -> Self {
276        Self { disabled: SanitizerSet::empty(), rtsan_setting: RtsanSetting::default() }
277    }
278}