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 /// The `#[rustc_objc_class = "..."]` attribute.
73 pub objc_class: Option<Symbol>,
74 /// The `#[rustc_objc_selector = "..."]` attribute.
75 pub objc_selector: Option<Symbol>,
76}
77
78#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)]
79pub enum TargetFeatureKind {
80 /// The feature is implied by another feature, rather than explicitly added by the
81 /// `#[target_feature]` attribute
82 Implied,
83 /// The feature is added by the regular `target_feature` attribute.
84 Enabled,
85 /// The feature is added by the unsafe `force_target_feature` attribute.
86 Forced,
87}
88
89#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)]
90pub struct TargetFeature {
91 /// The name of the target feature (e.g. "avx")
92 pub name: Symbol,
93 /// The way this feature was enabled.
94 pub kind: TargetFeatureKind,
95}
96
97#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
98pub struct PatchableFunctionEntry {
99 /// Nops to prepend to the function
100 prefix: u8,
101 /// Nops after entry, but before body
102 entry: u8,
103}
104
105impl PatchableFunctionEntry {
106 pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self {
107 Self { prefix: config.prefix(), entry: config.entry() }
108 }
109 pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self {
110 Self { prefix, entry }
111 }
112 pub fn prefix(&self) -> u8 {
113 self.prefix
114 }
115 pub fn entry(&self) -> u8 {
116 self.entry
117 }
118}
119
120#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
121pub struct CodegenFnAttrFlags(u32);
122bitflags::bitflags! {
123 impl CodegenFnAttrFlags: u32 {
124 /// `#[cold]`: a hint to LLVM that this function, when called, is never on
125 /// the hot path.
126 const COLD = 1 << 0;
127 /// `#[rustc_nounwind]`: An indicator that function will never unwind.
128 const NEVER_UNWIND = 1 << 1;
129 /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue
130 /// should be generated.
131 const NAKED = 1 << 2;
132 /// `#[no_mangle]`: an indicator that the function's name should be the same
133 /// as its symbol.
134 const NO_MANGLE = 1 << 3;
135 /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a
136 /// "weird symbol" for the standard library in that it has slightly
137 /// different linkage, visibility, and reachability rules.
138 const RUSTC_STD_INTERNAL_SYMBOL = 1 << 4;
139 /// `#[thread_local]`: indicates a static is actually a thread local
140 /// piece of memory
141 const THREAD_LOCAL = 1 << 5;
142 /// `#[used(compiler)]`: indicates that LLVM can't eliminate this function (but the
143 /// linker can!).
144 const USED_COMPILER = 1 << 6;
145 /// `#[used(linker)]`:
146 /// indicates that neither LLVM nor the linker will eliminate this function.
147 const USED_LINKER = 1 << 7;
148 /// `#[track_caller]`: allow access to the caller location
149 const TRACK_CALLER = 1 << 8;
150 /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
151 /// declaration.
152 const FFI_PURE = 1 << 9;
153 /// #[ffi_const]: applies clang's `const` attribute to a foreign function
154 /// declaration.
155 const FFI_CONST = 1 << 10;
156 /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
157 /// function is never null and the function has no side effects other than allocating.
158 const ALLOCATOR = 1 << 11;
159 /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
160 const DEALLOCATOR = 1 << 12;
161 /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
162 const REALLOCATOR = 1 << 13;
163 /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
164 const ALLOCATOR_ZEROED = 1 << 14;
165 /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
166 const NO_BUILTINS = 1 << 15;
167 /// Marks foreign items, to make `contains_extern_indicator` cheaper.
168 const FOREIGN_ITEM = 1 << 16;
169 }
170}
171rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
172
173impl CodegenFnAttrs {
174 pub const EMPTY: &'static Self = &Self::new();
175
176 pub const fn new() -> CodegenFnAttrs {
177 CodegenFnAttrs {
178 flags: CodegenFnAttrFlags::empty(),
179 inline: InlineAttr::None,
180 optimize: OptimizeAttr::Default,
181 symbol_name: None,
182 link_ordinal: None,
183 target_features: vec![],
184 safe_target_features: false,
185 linkage: None,
186 import_linkage: None,
187 link_section: None,
188 no_sanitize: SanitizerSet::empty(),
189 instruction_set: None,
190 alignment: None,
191 patchable_function_entry: None,
192 objc_class: None,
193 objc_selector: None,
194 }
195 }
196
197 /// Returns `true` if it looks like this symbol needs to be exported, for example:
198 ///
199 /// * `#[no_mangle]` is present
200 /// * `#[export_name(...)]` is present
201 /// * `#[linkage]` is present
202 ///
203 /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.
204 pub fn contains_extern_indicator(&self) -> bool {
205 if self.flags.contains(CodegenFnAttrFlags::FOREIGN_ITEM) {
206 return false;
207 }
208
209 self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
210 || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
211 || self.symbol_name.is_some()
212 || match self.linkage {
213 // These are private, so make sure we don't try to consider
214 // them external.
215 None | Some(Linkage::Internal) => false,
216 Some(_) => true,
217 }
218 }
219}