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