1use std::cell::RefCell;
2use std::collections::BTreeMap;
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::sync::LazyLock;
6
7use private::Sealed;
8use rustc_ast::{self as ast, MetaItemLit, NodeId};
9use rustc_attr_data_structures::AttributeKind;
10use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
11use rustc_errors::{DiagCtxtHandle, Diagnostic};
12use rustc_feature::{AttributeTemplate, Features};
13use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
14use rustc_session::Session;
15use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
16
17use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
18use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser};
19use crate::attributes::confusables::ConfusablesParser;
20use crate::attributes::deprecation::DeprecationParser;
21use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
22use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
23use crate::attributes::must_use::MustUseParser;
24use crate::attributes::repr::{AlignParser, ReprParser};
25use crate::attributes::semantics::MayDangleParser;
26use crate::attributes::stability::{
27 BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
28};
29use crate::attributes::transparency::TransparencyParser;
30use crate::attributes::{AttributeParser as _, Combine, Single};
31use crate::parser::{ArgParser, MetaItemParser};
32use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
33
34macro_rules! group_type {
35 ($stage: ty) => {
36 LazyLock<(
37 BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
38 Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
39 )>
40 };
41}
42
43macro_rules! attribute_parsers {
44 (
45 pub(crate) static $name: ident = [$($names: ty),* $(,)?];
46 ) => {
47 mod early {
48 use super::*;
49 type Combine<T> = super::Combine<T, Early>;
50 type Single<T> = super::Single<T, Early>;
51
52 attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
53 }
54 mod late {
55 use super::*;
56 type Combine<T> = super::Combine<T, Late>;
57 type Single<T> = super::Single<T, Late>;
58
59 attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
60 }
61 };
62 (
63 @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
64 ) => {
65 pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
66 let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
67 let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
68 $(
69 {
70 thread_local! {
71 static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
72 };
73
74 for (path, template, accept_fn) in <$names>::ATTRIBUTES {
75 accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
76 STATE_OBJECT.with_borrow_mut(|s| {
77 accept_fn(s, cx, args)
78 })
79 })));
80 }
81
82 finalizes.push(Box::new(|cx| {
83 let state = STATE_OBJECT.take();
84 state.finalize(cx)
85 }));
86 }
87 )*
88
89 (accepts, finalizes)
90 });
91 };
92}
93attribute_parsers!(
94 pub(crate) static ATTRIBUTE_PARSERS = [
95 AlignParser,
97 BodyStabilityParser,
98 ConfusablesParser,
99 ConstStabilityParser,
100 StabilityParser,
101 Combine<AllowConstFnUnstableParser>,
105 Combine<AllowInternalUnstableParser>,
106 Combine<ReprParser>,
107 Single<AsPtrParser>,
111 Single<ColdParser>,
112 Single<ConstStabilityIndirectParser>,
113 Single<DeprecationParser>,
114 Single<InlineParser>,
115 Single<MayDangleParser>,
116 Single<MustUseParser>,
117 Single<NoMangleParser>,
118 Single<OptimizeParser>,
119 Single<PubTransparentParser>,
120 Single<RustcForceInlineParser>,
121 Single<TransparencyParser>,
122 ];
124);
125
126mod private {
127 pub trait Sealed {}
128 impl Sealed for super::Early {}
129 impl Sealed for super::Late {}
130}
131
132#[allow(private_interfaces)]
134pub trait Stage: Sized + 'static + Sealed {
135 type Id: Copy;
136
137 fn parsers() -> &'static group_type!(Self);
138
139 fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
140}
141
142#[allow(private_interfaces)]
144impl Stage for Early {
145 type Id = NodeId;
146
147 fn parsers() -> &'static group_type!(Self) {
148 &early::ATTRIBUTE_PARSERS
149 }
150 fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
151 sess.dcx().create_err(diag).delay_as_bug()
152 }
153}
154
155#[allow(private_interfaces)]
157impl Stage for Late {
158 type Id = HirId;
159
160 fn parsers() -> &'static group_type!(Self) {
161 &late::ATTRIBUTE_PARSERS
162 }
163 fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
164 tcx.dcx().emit_err(diag)
165 }
166}
167
168pub struct Early;
170pub struct Late;
172
173pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
177 pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>,
178 pub(crate) attr_span: Span,
180
181 pub(crate) template: &'f AttributeTemplate,
185
186 pub(crate) attr_path: AttrPath,
188}
189
190impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
191 pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
192 S::emit_err(&self.sess, diag)
193 }
194
195 pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
199 let id = self.target_id;
200 (self.emit_lint)(AttributeLint { id, span, kind: lint });
201 }
202
203 pub(crate) fn unknown_key(
204 &self,
205 span: Span,
206 found: String,
207 options: &'static [&'static str],
208 ) -> ErrorGuaranteed {
209 self.emit_err(UnknownMetaItem { span, item: found, expected: options })
210 }
211
212 pub(crate) fn expected_string_literal(
217 &self,
218 span: Span,
219 actual_literal: Option<&MetaItemLit>,
220 ) -> ErrorGuaranteed {
221 self.emit_err(AttributeParseError {
222 span,
223 attr_span: self.attr_span,
224 template: self.template.clone(),
225 attribute: self.attr_path.clone(),
226 reason: AttributeParseErrorReason::ExpectedStringLiteral {
227 byte_string: actual_literal.and_then(|i| {
228 i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
229 }),
230 },
231 })
232 }
233
234 pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
235 self.emit_err(AttributeParseError {
236 span,
237 attr_span: self.attr_span,
238 template: self.template.clone(),
239 attribute: self.attr_path.clone(),
240 reason: AttributeParseErrorReason::ExpectedList,
241 })
242 }
243
244 pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
245 self.emit_err(AttributeParseError {
246 span: args_span,
247 attr_span: self.attr_span,
248 template: self.template.clone(),
249 attribute: self.attr_path.clone(),
250 reason: AttributeParseErrorReason::ExpectedNoArgs,
251 })
252 }
253
254 pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
257 self.emit_err(AttributeParseError {
258 span,
259 attr_span: self.attr_span,
260 template: self.template.clone(),
261 attribute: self.attr_path.clone(),
262 reason: AttributeParseErrorReason::ExpectedNameValue(name),
263 })
264 }
265
266 pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
268 self.emit_err(AttributeParseError {
269 span,
270 attr_span: self.attr_span,
271 template: self.template.clone(),
272 attribute: self.attr_path.clone(),
273 reason: AttributeParseErrorReason::DuplicateKey(key),
274 })
275 }
276
277 pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
280 self.emit_err(AttributeParseError {
281 span,
282 attr_span: self.attr_span,
283 template: self.template.clone(),
284 attribute: self.attr_path.clone(),
285 reason: AttributeParseErrorReason::UnexpectedLiteral,
286 })
287 }
288
289 pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
290 self.emit_err(AttributeParseError {
291 span,
292 attr_span: self.attr_span,
293 template: self.template.clone(),
294 attribute: self.attr_path.clone(),
295 reason: AttributeParseErrorReason::ExpectedSingleArgument,
296 })
297 }
298
299 pub(crate) fn expected_specific_argument(
300 &self,
301 span: Span,
302 possibilities: Vec<&'static str>,
303 ) -> ErrorGuaranteed {
304 self.emit_err(AttributeParseError {
305 span,
306 attr_span: self.attr_span,
307 template: self.template.clone(),
308 attribute: self.attr_path.clone(),
309 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
310 possibilities,
311 strings: false,
312 },
313 })
314 }
315
316 pub(crate) fn expected_specific_argument_strings(
317 &self,
318 span: Span,
319 possibilities: Vec<&'static str>,
320 ) -> ErrorGuaranteed {
321 self.emit_err(AttributeParseError {
322 span,
323 attr_span: self.attr_span,
324 template: self.template.clone(),
325 attribute: self.attr_path.clone(),
326 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
327 possibilities,
328 strings: true,
329 },
330 })
331 }
332}
333
334impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
335 type Target = FinalizeContext<'f, 'sess, S>;
336
337 fn deref(&self) -> &Self::Target {
338 &self.finalize_cx
339 }
340}
341
342impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
343 fn deref_mut(&mut self) -> &mut Self::Target {
344 &mut self.finalize_cx
345 }
346}
347
348pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
353 pub(crate) cx: &'p mut AttributeParser<'sess, S>,
356 pub(crate) target_span: Span,
358 pub(crate) target_id: S::Id,
360
361 pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
362}
363
364impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
365 type Target = AttributeParser<'sess, S>;
366
367 fn deref(&self) -> &Self::Target {
368 self.cx
369 }
370}
371
372impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
373 fn deref_mut(&mut self) -> &mut Self::Target {
374 self.cx
375 }
376}
377
378#[derive(PartialEq, Clone, Copy, Debug)]
379pub enum OmitDoc {
380 Lower,
381 Skip,
382}
383
384pub struct AttributeParser<'sess, S: Stage = Late> {
387 #[expect(dead_code)] tools: Vec<Symbol>,
389 features: Option<&'sess Features>,
390 sess: &'sess Session,
391 stage: PhantomData<S>,
392
393 parse_only: Option<Symbol>,
397}
398
399impl<'sess> AttributeParser<'sess, Early> {
400 pub fn parse_limited(
415 sess: &'sess Session,
416 attrs: &[ast::Attribute],
417 sym: Symbol,
418 target_span: Span,
419 target_node_id: NodeId,
420 ) -> Option<Attribute> {
421 let mut p = Self {
422 features: None,
423 tools: Vec::new(),
424 parse_only: Some(sym),
425 sess,
426 stage: PhantomData,
427 };
428 let mut parsed = p.parse_attribute_list(
429 attrs,
430 target_span,
431 target_node_id,
432 OmitDoc::Skip,
433 std::convert::identity,
434 |_lint| {
435 panic!("can't emit lints here for now (nothing uses this atm)");
436 },
437 );
438 assert!(parsed.len() <= 1);
439
440 parsed.pop()
441 }
442}
443
444impl<'sess, S: Stage> AttributeParser<'sess, S> {
445 pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
446 Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
447 }
448
449 pub(crate) fn sess(&self) -> &'sess Session {
450 &self.sess
451 }
452
453 pub(crate) fn features(&self) -> &'sess Features {
454 self.features.expect("features not available at this point in the compiler")
455 }
456
457 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
458 self.sess().dcx()
459 }
460
461 pub fn parse_attribute_list(
466 &mut self,
467 attrs: &[ast::Attribute],
468 target_span: Span,
469 target_id: S::Id,
470 omit_doc: OmitDoc,
471
472 lower_span: impl Copy + Fn(Span) -> Span,
473 mut emit_lint: impl FnMut(AttributeLint<S::Id>),
474 ) -> Vec<Attribute> {
475 let mut attributes = Vec::new();
476
477 for attr in attrs {
478 if let Some(expected) = self.parse_only {
480 if !attr.has_name(expected) {
481 continue;
482 }
483 }
484
485 if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
491 continue;
492 }
493
494 match &attr.kind {
495 ast::AttrKind::DocComment(comment_kind, symbol) => {
496 if omit_doc == OmitDoc::Skip {
497 continue;
498 }
499
500 attributes.push(Attribute::Parsed(AttributeKind::DocComment {
501 style: attr.style,
502 kind: *comment_kind,
503 span: lower_span(attr.span),
504 comment: *symbol,
505 }))
506 }
507 ast::AttrKind::Normal(n) => {
519 let parser = MetaItemParser::from_attr(n, self.dcx());
520 let path = parser.path();
521 let args = parser.args();
522 let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
523
524 if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
525 for (template, accept) in accepts {
526 let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
527 finalize_cx: FinalizeContext {
528 cx: self,
529 target_span,
530 target_id,
531 emit_lint: &mut emit_lint,
532 },
533 attr_span: lower_span(attr.span),
534 template,
535 attr_path: path.get_attribute_path(),
536 };
537
538 accept(&mut cx, args)
539 }
540 } else {
541 attributes.push(Attribute::Unparsed(Box::new(AttrItem {
557 path: AttrPath::from_ast(&n.item.path),
558 args: self.lower_attr_args(&n.item.args, lower_span),
559 id: HashIgnoredAttrId { attr_id: attr.id },
560 style: attr.style,
561 span: lower_span(attr.span),
562 })));
563 }
564 }
565 }
566 }
567
568 let mut parsed_attributes = Vec::new();
569 for f in &S::parsers().1 {
570 if let Some(attr) = f(&mut FinalizeContext {
571 cx: self,
572 target_span,
573 target_id,
574 emit_lint: &mut emit_lint,
575 }) {
576 parsed_attributes.push(Attribute::Parsed(attr));
577 }
578 }
579
580 attributes.extend(parsed_attributes);
581
582 attributes
583 }
584
585 fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
586 match args {
587 ast::AttrArgs::Empty => AttrArgs::Empty,
588 ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()),
589 ast::AttrArgs::Eq { eq_span, expr } => {
593 let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
596 && let Ok(lit) =
597 ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
598 {
599 lit
600 } else {
601 let guar = self.dcx().span_delayed_bug(
602 args.span().unwrap_or(DUMMY_SP),
603 "expr in place where literal is expected (builtin attr parsing)",
604 );
605 ast::MetaItemLit {
606 symbol: sym::dummy,
607 suffix: None,
608 kind: ast::LitKind::Err(guar),
609 span: DUMMY_SP,
610 }
611 };
612 AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
613 }
614 }
615 }
616}