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