rustc_attr_parsing/attributes/
codegen_attrs.rs1use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
2use rustc_feature::{AttributeTemplate, template};
3use rustc_session::parse::feature_err;
4use rustc_span::{Span, Symbol, sym};
5
6use super::{
7 AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
8 NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
9};
10use crate::context::{AcceptContext, FinalizeContext, Stage};
11use crate::parser::ArgParser;
12use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
13
14pub(crate) struct OptimizeParser;
15
16impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
17 const PATH: &[Symbol] = &[sym::optimize];
18 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
19 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
20 const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
21
22 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
23 let Some(list) = args.list() else {
24 cx.expected_list(cx.attr_span);
25 return None;
26 };
27
28 let Some(single) = list.single() else {
29 cx.expected_single_argument(list.span);
30 return None;
31 };
32
33 let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
34 Some(sym::size) => OptimizeAttr::Size,
35 Some(sym::speed) => OptimizeAttr::Speed,
36 Some(sym::none) => OptimizeAttr::DoNotOptimize,
37 _ => {
38 cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]);
39 OptimizeAttr::Default
40 }
41 };
42
43 Some(AttributeKind::Optimize(res, cx.attr_span))
44 }
45}
46
47pub(crate) struct ColdParser;
48
49impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
50 const PATH: &[Symbol] = &[sym::cold];
51 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
52 const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
53}
54
55pub(crate) struct CoverageParser;
56
57impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
58 const PATH: &[Symbol] = &[sym::coverage];
59 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
60 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
61 const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
62
63 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
64 let Some(args) = args.list() else {
65 cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]);
66 return None;
67 };
68
69 let Some(arg) = args.single() else {
70 cx.expected_single_argument(args.span);
71 return None;
72 };
73
74 let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]);
75
76 let Some(arg) = arg.meta_item() else {
77 fail_incorrect_argument(args.span);
78 return None;
79 };
80
81 let status = match arg.path().word_sym() {
82 Some(sym::off) => CoverageStatus::Off,
83 Some(sym::on) => CoverageStatus::On,
84 None | Some(_) => {
85 fail_incorrect_argument(arg.span());
86 return None;
87 }
88 };
89
90 Some(AttributeKind::Coverage(cx.attr_span, status))
91 }
92}
93
94pub(crate) struct ExportNameParser;
95
96impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
97 const PATH: &[rustc_span::Symbol] = &[sym::export_name];
98 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
99 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
100 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
101
102 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
103 let Some(nv) = args.name_value() else {
104 cx.expected_name_value(cx.attr_span, None);
105 return None;
106 };
107 let Some(name) = nv.value_as_str() else {
108 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
109 return None;
110 };
111 if name.as_str().contains('\0') {
112 cx.emit_err(NullOnExport { span: cx.attr_span });
115 return None;
116 }
117 Some(AttributeKind::ExportName { name, span: cx.attr_span })
118 }
119}
120
121#[derive(Default)]
122pub(crate) struct NakedParser {
123 span: Option<Span>,
124}
125
126impl<S: Stage> AttributeParser<S> for NakedParser {
127 const ATTRIBUTES: AcceptMapping<Self, S> =
128 &[(&[sym::naked], template!(Word), |this, cx, args| {
129 if let Err(span) = args.no_args() {
130 cx.expected_no_args(span);
131 return;
132 }
133
134 if let Some(earlier) = this.span {
135 let span = cx.attr_span;
136 cx.warn_unused_duplicate(earlier, span);
137 } else {
138 this.span = Some(cx.attr_span);
139 }
140 })];
141
142 fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
143 const ALLOW_LIST: &[rustc_span::Symbol] = &[
156 sym::cfg_trace,
158 sym::cfg_attr_trace,
159 sym::test,
161 sym::ignore,
162 sym::should_panic,
163 sym::bench,
164 sym::allow,
166 sym::warn,
167 sym::deny,
168 sym::forbid,
169 sym::deprecated,
170 sym::must_use,
171 sym::cold,
173 sym::export_name,
174 sym::link_section,
175 sym::linkage,
176 sym::no_mangle,
177 sym::instruction_set,
178 sym::repr,
179 sym::rustc_std_internal_symbol,
180 sym::align,
181 sym::naked,
183 sym::doc,
185 ];
186
187 let span = self.span?;
188
189 'outer: for other_attr in cx.all_attrs {
191 for allowed_attr in ALLOW_LIST {
192 if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
193 continue 'outer;
196 }
197 if other_attr.word_is(*allowed_attr) {
198 continue 'outer;
201 }
202
203 if other_attr.word_is(sym::target_feature) {
204 if !cx.features().naked_functions_target_feature() {
205 feature_err(
206 &cx.sess(),
207 sym::naked_functions_target_feature,
208 other_attr.span(),
209 "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
210 ).emit();
211 }
212
213 continue 'outer;
214 }
215 }
216
217 cx.emit_err(NakedFunctionIncompatibleAttribute {
218 span: other_attr.span(),
219 naked_span: span,
220 attr: other_attr.get_attribute_path().to_string(),
221 });
222 }
223
224 Some(AttributeKind::Naked(span))
225 }
226}
227
228pub(crate) struct TrackCallerParser;
229impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
230 const PATH: &[Symbol] = &[sym::track_caller];
231 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
232 const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
233}
234
235pub(crate) struct NoMangleParser;
236impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
237 const PATH: &[Symbol] = &[sym::no_mangle];
238 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
239 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
240}
241
242#[derive(Default)]
243pub(crate) struct UsedParser {
244 first_compiler: Option<Span>,
245 first_linker: Option<Span>,
246}
247
248impl<S: Stage> AttributeParser<S> for UsedParser {
253 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
254 &[sym::used],
255 template!(Word, List: "compiler|linker"),
256 |group: &mut Self, cx, args| {
257 let used_by = match args {
258 ArgParser::NoArgs => UsedBy::Linker,
259 ArgParser::List(list) => {
260 let Some(l) = list.single() else {
261 cx.expected_single_argument(list.span);
262 return;
263 };
264
265 match l.meta_item().and_then(|i| i.path().word_sym()) {
266 Some(sym::compiler) => {
267 if !cx.features().used_with_arg() {
268 feature_err(
269 &cx.sess(),
270 sym::used_with_arg,
271 cx.attr_span,
272 "`#[used(compiler)]` is currently unstable",
273 )
274 .emit();
275 }
276 UsedBy::Compiler
277 }
278 Some(sym::linker) => {
279 if !cx.features().used_with_arg() {
280 feature_err(
281 &cx.sess(),
282 sym::used_with_arg,
283 cx.attr_span,
284 "`#[used(linker)]` is currently unstable",
285 )
286 .emit();
287 }
288 UsedBy::Linker
289 }
290 _ => {
291 cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
292 return;
293 }
294 }
295 }
296 ArgParser::NameValue(_) => return,
297 };
298
299 let target = match used_by {
300 UsedBy::Compiler => &mut group.first_compiler,
301 UsedBy::Linker => &mut group.first_linker,
302 };
303
304 let attr_span = cx.attr_span;
305 if let Some(prev) = *target {
306 cx.warn_unused_duplicate(prev, attr_span);
307 } else {
308 *target = Some(attr_span);
309 }
310 },
311 )];
312
313 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
314 Some(match (self.first_compiler, self.first_linker) {
316 (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
317 (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
318 (None, None) => return None,
319 })
320 }
321}
322
323pub(crate) struct TargetFeatureParser;
324
325impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
326 type Item = (Symbol, Span);
327 const PATH: &[Symbol] = &[sym::target_feature];
328 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
329 const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
330
331 fn extend<'c>(
332 cx: &'c mut AcceptContext<'_, '_, S>,
333 args: &'c ArgParser<'_>,
334 ) -> impl IntoIterator<Item = Self::Item> + 'c {
335 let mut features = Vec::new();
336 let ArgParser::List(list) = args else {
337 cx.expected_list(cx.attr_span);
338 return features;
339 };
340 if list.is_empty() {
341 cx.warn_empty_attribute(cx.attr_span);
342 return features;
343 }
344 for item in list.mixed() {
345 let Some(name_value) = item.meta_item() else {
346 cx.expected_name_value(item.span(), Some(sym::enable));
347 return features;
348 };
349
350 let Some(name) = name_value.path().word_sym() else {
352 cx.expected_name_value(name_value.path().span(), Some(sym::enable));
353 return features;
354 };
355 if name != sym::enable {
356 cx.expected_name_value(name_value.path().span(), Some(sym::enable));
357 return features;
358 }
359
360 let Some(name_value) = name_value.args().name_value() else {
362 cx.expected_name_value(item.span(), Some(sym::enable));
363 return features;
364 };
365 let Some(value_str) = name_value.value_as_str() else {
366 cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
367 return features;
368 };
369 for feature in value_str.as_str().split(",") {
370 features.push((Symbol::intern(feature), item.span()));
371 }
372 }
373 features
374 }
375}
376
377pub(crate) struct OmitGdbPrettyPrinterSectionParser;
378
379impl<S: Stage> NoArgsAttributeParser<S> for OmitGdbPrettyPrinterSectionParser {
380 const PATH: &[Symbol] = &[sym::omit_gdb_pretty_printer_section];
381 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
382 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::OmitGdbPrettyPrinterSection;
383}