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}