rustc_attr_parsing/attributes/
codegen_attrs.rs1use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
2use rustc_feature::{AttributeTemplate, template};
3use rustc_session::parse::feature_err;
4use rustc_span::{Span, Symbol, sym};
5
6use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
7use crate::context::{AcceptContext, FinalizeContext, Stage};
8use crate::parser::ArgParser;
9use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
10
11pub(crate) struct OptimizeParser;
12
13impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
14 const PATH: &[Symbol] = &[sym::optimize];
15 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
16 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
17 const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
18
19 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
20 let Some(list) = args.list() else {
21 cx.expected_list(cx.attr_span);
22 return None;
23 };
24
25 let Some(single) = list.single() else {
26 cx.expected_single_argument(list.span);
27 return None;
28 };
29
30 let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
31 Some(sym::size) => OptimizeAttr::Size,
32 Some(sym::speed) => OptimizeAttr::Speed,
33 Some(sym::none) => OptimizeAttr::DoNotOptimize,
34 _ => {
35 cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]);
36 OptimizeAttr::Default
37 }
38 };
39
40 Some(AttributeKind::Optimize(res, cx.attr_span))
41 }
42}
43
44pub(crate) struct ColdParser;
45
46impl<S: Stage> SingleAttributeParser<S> for ColdParser {
47 const PATH: &[Symbol] = &[sym::cold];
48 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
49 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
50 const TEMPLATE: AttributeTemplate = template!(Word);
51
52 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
53 if let Err(span) = args.no_args() {
54 cx.expected_no_args(span);
55 return None;
56 }
57
58 Some(AttributeKind::Cold(cx.attr_span))
59 }
60}
61
62pub(crate) struct ExportNameParser;
63
64impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
65 const PATH: &[rustc_span::Symbol] = &[sym::export_name];
66 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
67 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
68 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
69
70 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
71 let Some(nv) = args.name_value() else {
72 cx.expected_name_value(cx.attr_span, None);
73 return None;
74 };
75 let Some(name) = nv.value_as_str() else {
76 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
77 return None;
78 };
79 if name.as_str().contains('\0') {
80 cx.emit_err(NullOnExport { span: cx.attr_span });
83 return None;
84 }
85 Some(AttributeKind::ExportName { name, span: cx.attr_span })
86 }
87}
88
89#[derive(Default)]
90pub(crate) struct NakedParser {
91 span: Option<Span>,
92}
93
94impl<S: Stage> AttributeParser<S> for NakedParser {
95 const ATTRIBUTES: AcceptMapping<Self, S> =
96 &[(&[sym::naked], template!(Word), |this, cx, args| {
97 if let Err(span) = args.no_args() {
98 cx.expected_no_args(span);
99 return;
100 }
101
102 if let Some(earlier) = this.span {
103 let span = cx.attr_span;
104 cx.warn_unused_duplicate(earlier, span);
105 } else {
106 this.span = Some(cx.attr_span);
107 }
108 })];
109
110 fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
111 const ALLOW_LIST: &[rustc_span::Symbol] = &[
124 sym::cfg_trace,
126 sym::cfg_attr_trace,
127 sym::test,
129 sym::ignore,
130 sym::should_panic,
131 sym::bench,
132 sym::allow,
134 sym::warn,
135 sym::deny,
136 sym::forbid,
137 sym::deprecated,
138 sym::must_use,
139 sym::cold,
141 sym::export_name,
142 sym::link_section,
143 sym::linkage,
144 sym::no_mangle,
145 sym::instruction_set,
146 sym::repr,
147 sym::rustc_std_internal_symbol,
148 sym::align,
149 sym::naked,
151 sym::doc,
153 ];
154
155 let span = self.span?;
156
157 'outer: for other_attr in cx.all_attrs {
159 for allowed_attr in ALLOW_LIST {
160 if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
161 continue 'outer;
164 }
165 if other_attr.word_is(*allowed_attr) {
166 continue 'outer;
169 }
170
171 if other_attr.word_is(sym::target_feature) {
172 if !cx.features().naked_functions_target_feature() {
173 feature_err(
174 &cx.sess(),
175 sym::naked_functions_target_feature,
176 other_attr.span(),
177 "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
178 ).emit();
179 }
180
181 continue 'outer;
182 }
183 }
184
185 cx.emit_err(NakedFunctionIncompatibleAttribute {
186 span: other_attr.span(),
187 naked_span: span,
188 attr: other_attr.get_attribute_path().to_string(),
189 });
190 }
191
192 Some(AttributeKind::Naked(span))
193 }
194}
195
196pub(crate) struct TrackCallerParser;
197
198impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser {
199 const PATH: &[Symbol] = &[sym::track_caller];
200 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
201 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
202 const TEMPLATE: AttributeTemplate = template!(Word);
203
204 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
205 if let Err(span) = args.no_args() {
206 cx.expected_no_args(span);
207 return None;
208 }
209
210 Some(AttributeKind::TrackCaller(cx.attr_span))
211 }
212}
213
214pub(crate) struct NoMangleParser;
215
216impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
217 const PATH: &[rustc_span::Symbol] = &[sym::no_mangle];
218 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
219 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
220 const TEMPLATE: AttributeTemplate = template!(Word);
221
222 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
223 if let Err(span) = args.no_args() {
224 cx.expected_no_args(span);
225 return None;
226 }
227
228 Some(AttributeKind::NoMangle(cx.attr_span))
229 }
230}
231
232#[derive(Default)]
233pub(crate) struct UsedParser {
234 first_compiler: Option<Span>,
235 first_linker: Option<Span>,
236}
237
238impl<S: Stage> AttributeParser<S> for UsedParser {
243 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
244 &[sym::used],
245 template!(Word, List: "compiler|linker"),
246 |group: &mut Self, cx, args| {
247 let used_by = match args {
248 ArgParser::NoArgs => UsedBy::Linker,
249 ArgParser::List(list) => {
250 let Some(l) = list.single() else {
251 cx.expected_single_argument(list.span);
252 return;
253 };
254
255 match l.meta_item().and_then(|i| i.path().word_sym()) {
256 Some(sym::compiler) => {
257 if !cx.features().used_with_arg() {
258 feature_err(
259 &cx.sess(),
260 sym::used_with_arg,
261 cx.attr_span,
262 "`#[used(compiler)]` is currently unstable",
263 )
264 .emit();
265 }
266 UsedBy::Compiler
267 }
268 Some(sym::linker) => {
269 if !cx.features().used_with_arg() {
270 feature_err(
271 &cx.sess(),
272 sym::used_with_arg,
273 cx.attr_span,
274 "`#[used(linker)]` is currently unstable",
275 )
276 .emit();
277 }
278 UsedBy::Linker
279 }
280 _ => {
281 cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
282 return;
283 }
284 }
285 }
286 ArgParser::NameValue(_) => return,
287 };
288
289 let target = match used_by {
290 UsedBy::Compiler => &mut group.first_compiler,
291 UsedBy::Linker => &mut group.first_linker,
292 };
293
294 let attr_span = cx.attr_span;
295 if let Some(prev) = *target {
296 cx.warn_unused_duplicate(prev, attr_span);
297 } else {
298 *target = Some(attr_span);
299 }
300 },
301 )];
302
303 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
304 Some(match (self.first_compiler, self.first_linker) {
306 (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
307 (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
308 (None, None) => return None,
309 })
310 }
311}