rustc_attr_parsing/attributes/
codegen_attrs.rs1use rustc_feature::{AttributeTemplate, template};
2use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy};
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 kind = match arg.path().word_sym() {
82 Some(sym::off) => CoverageAttrKind::Off,
83 Some(sym::on) => CoverageAttrKind::On,
84 None | Some(_) => {
85 fail_incorrect_argument(arg.span());
86 return None;
87 }
88 };
89
90 Some(AttributeKind::Coverage(cx.attr_span, kind))
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::rustc_align,
182 sym::naked,
184 sym::doc,
186 ];
187
188 let span = self.span?;
189
190 'outer: for other_attr in cx.all_attrs {
192 for allowed_attr in ALLOW_LIST {
193 if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
194 continue 'outer;
197 }
198 if other_attr.word_is(*allowed_attr) {
199 continue 'outer;
202 }
203
204 if other_attr.word_is(sym::target_feature) {
205 if !cx.features().naked_functions_target_feature() {
206 feature_err(
207 &cx.sess(),
208 sym::naked_functions_target_feature,
209 other_attr.span(),
210 "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
211 ).emit();
212 }
213
214 continue 'outer;
215 }
216 }
217
218 cx.emit_err(NakedFunctionIncompatibleAttribute {
219 span: other_attr.span(),
220 naked_span: span,
221 attr: other_attr.get_attribute_path().to_string(),
222 });
223 }
224
225 Some(AttributeKind::Naked(span))
226 }
227}
228
229pub(crate) struct TrackCallerParser;
230impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
231 const PATH: &[Symbol] = &[sym::track_caller];
232 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
233 const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
234}
235
236pub(crate) struct NoMangleParser;
237impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
238 const PATH: &[Symbol] = &[sym::no_mangle];
239 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
240 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
241}
242
243#[derive(Default)]
244pub(crate) struct UsedParser {
245 first_compiler: Option<Span>,
246 first_linker: Option<Span>,
247}
248
249impl<S: Stage> AttributeParser<S> for UsedParser {
254 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
255 &[sym::used],
256 template!(Word, List: "compiler|linker"),
257 |group: &mut Self, cx, args| {
258 let used_by = match args {
259 ArgParser::NoArgs => UsedBy::Linker,
260 ArgParser::List(list) => {
261 let Some(l) = list.single() else {
262 cx.expected_single_argument(list.span);
263 return;
264 };
265
266 match l.meta_item().and_then(|i| i.path().word_sym()) {
267 Some(sym::compiler) => {
268 if !cx.features().used_with_arg() {
269 feature_err(
270 &cx.sess(),
271 sym::used_with_arg,
272 cx.attr_span,
273 "`#[used(compiler)]` is currently unstable",
274 )
275 .emit();
276 }
277 UsedBy::Compiler
278 }
279 Some(sym::linker) => {
280 if !cx.features().used_with_arg() {
281 feature_err(
282 &cx.sess(),
283 sym::used_with_arg,
284 cx.attr_span,
285 "`#[used(linker)]` is currently unstable",
286 )
287 .emit();
288 }
289 UsedBy::Linker
290 }
291 _ => {
292 cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
293 return;
294 }
295 }
296 }
297 ArgParser::NameValue(_) => return,
298 };
299
300 let target = match used_by {
301 UsedBy::Compiler => &mut group.first_compiler,
302 UsedBy::Linker => &mut group.first_linker,
303 };
304
305 let attr_span = cx.attr_span;
306 if let Some(prev) = *target {
307 cx.warn_unused_duplicate(prev, attr_span);
308 } else {
309 *target = Some(attr_span);
310 }
311 },
312 )];
313
314 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
315 Some(match (self.first_compiler, self.first_linker) {
317 (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
318 (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
319 (None, None) => return None,
320 })
321 }
322}
323
324pub(crate) struct TargetFeatureParser;
325
326impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
327 type Item = (Symbol, Span);
328 const PATH: &[Symbol] = &[sym::target_feature];
329 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
330 const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
331
332 fn extend<'c>(
333 cx: &'c mut AcceptContext<'_, '_, S>,
334 args: &'c ArgParser<'_>,
335 ) -> impl IntoIterator<Item = Self::Item> + 'c {
336 let mut features = Vec::new();
337 let ArgParser::List(list) = args else {
338 cx.expected_list(cx.attr_span);
339 return features;
340 };
341 if list.is_empty() {
342 cx.warn_empty_attribute(cx.attr_span);
343 return features;
344 }
345 for item in list.mixed() {
346 let Some(name_value) = item.meta_item() else {
347 cx.expected_name_value(item.span(), Some(sym::enable));
348 return features;
349 };
350
351 let Some(name) = name_value.path().word_sym() else {
353 cx.expected_name_value(name_value.path().span(), Some(sym::enable));
354 return features;
355 };
356 if name != sym::enable {
357 cx.expected_name_value(name_value.path().span(), Some(sym::enable));
358 return features;
359 }
360
361 let Some(name_value) = name_value.args().name_value() else {
363 cx.expected_name_value(item.span(), Some(sym::enable));
364 return features;
365 };
366 let Some(value_str) = name_value.value_as_str() else {
367 cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
368 return features;
369 };
370 for feature in value_str.as_str().split(",") {
371 features.push((Symbol::intern(feature), item.span()));
372 }
373 }
374 features
375 }
376}
377
378pub(crate) struct OmitGdbPrettyPrinterSectionParser;
379
380impl<S: Stage> NoArgsAttributeParser<S> for OmitGdbPrettyPrinterSectionParser {
381 const PATH: &[Symbol] = &[sym::omit_gdb_pretty_printer_section];
382 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
383 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::OmitGdbPrettyPrinterSection;
384}