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::{
19 ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
20 UsedParser,
21};
22use crate::attributes::confusables::ConfusablesParser;
23use crate::attributes::deprecation::DeprecationParser;
24use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
25use crate::attributes::link_attrs::LinkNameParser;
26use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
27use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
28use crate::attributes::must_use::MustUseParser;
29use crate::attributes::repr::{AlignParser, ReprParser};
30use crate::attributes::semantics::MayDangleParser;
31use crate::attributes::stability::{
32 BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
33};
34use crate::attributes::traits::SkipDuringMethodDispatchParser;
35use crate::attributes::transparency::TransparencyParser;
36use crate::attributes::{AttributeParser as _, Combine, Single};
37use crate::parser::{ArgParser, MetaItemParser, PathParser};
38use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
39
40macro_rules! group_type {
41 ($stage: ty) => {
42 LazyLock<(
43 BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
44 Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
45 )>
46 };
47}
48
49macro_rules! attribute_parsers {
50 (
51 pub(crate) static $name: ident = [$($names: ty),* $(,)?];
52 ) => {
53 mod early {
54 use super::*;
55 type Combine<T> = super::Combine<T, Early>;
56 type Single<T> = super::Single<T, Early>;
57
58 attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
59 }
60 mod late {
61 use super::*;
62 type Combine<T> = super::Combine<T, Late>;
63 type Single<T> = super::Single<T, Late>;
64
65 attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
66 }
67 };
68 (
69 @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
70 ) => {
71 pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
72 let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
73 let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
74 $(
75 {
76 thread_local! {
77 static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
78 };
79
80 for (path, template, accept_fn) in <$names>::ATTRIBUTES {
81 accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
82 STATE_OBJECT.with_borrow_mut(|s| {
83 accept_fn(s, cx, args)
84 })
85 })));
86 }
87
88 finalizes.push(Box::new(|cx| {
89 let state = STATE_OBJECT.take();
90 state.finalize(cx)
91 }));
92 }
93 )*
94
95 (accepts, finalizes)
96 });
97 };
98}
99attribute_parsers!(
100 pub(crate) static ATTRIBUTE_PARSERS = [
101 AlignParser,
103 BodyStabilityParser,
104 ConfusablesParser,
105 ConstStabilityParser,
106 NakedParser,
107 StabilityParser,
108 UsedParser,
109 Combine<AllowConstFnUnstableParser>,
113 Combine<AllowInternalUnstableParser>,
114 Combine<ReprParser>,
115 Single<AsPtrParser>,
119 Single<ColdParser>,
120 Single<ConstContinueParser>,
121 Single<ConstStabilityIndirectParser>,
122 Single<DeprecationParser>,
123 Single<ExportNameParser>,
124 Single<InlineParser>,
125 Single<LinkNameParser>,
126 Single<LoopMatchParser>,
127 Single<MayDangleParser>,
128 Single<MustUseParser>,
129 Single<NoMangleParser>,
130 Single<OptimizeParser>,
131 Single<PubTransparentParser>,
132 Single<RustcForceInlineParser>,
133 Single<SkipDuringMethodDispatchParser>,
134 Single<TrackCallerParser>,
135 Single<TransparencyParser>,
136 ];
138);
139
140mod private {
141 pub trait Sealed {}
142 impl Sealed for super::Early {}
143 impl Sealed for super::Late {}
144}
145
146#[allow(private_interfaces)]
148pub trait Stage: Sized + 'static + Sealed {
149 type Id: Copy;
150
151 fn parsers() -> &'static group_type!(Self);
152
153 fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
154}
155
156#[allow(private_interfaces)]
158impl Stage for Early {
159 type Id = NodeId;
160
161 fn parsers() -> &'static group_type!(Self) {
162 &early::ATTRIBUTE_PARSERS
163 }
164 fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
165 sess.dcx().create_err(diag).delay_as_bug()
166 }
167}
168
169#[allow(private_interfaces)]
171impl Stage for Late {
172 type Id = HirId;
173
174 fn parsers() -> &'static group_type!(Self) {
175 &late::ATTRIBUTE_PARSERS
176 }
177 fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
178 tcx.dcx().emit_err(diag)
179 }
180}
181
182pub struct Early;
184pub struct Late;
186
187pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
191 pub(crate) shared: SharedContext<'f, 'sess, S>,
192 pub(crate) attr_span: Span,
194
195 pub(crate) template: &'f AttributeTemplate,
199
200 pub(crate) attr_path: AttrPath,
202}
203
204impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
205 pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
206 S::emit_err(&self.sess, diag)
207 }
208
209 pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
213 let id = self.target_id;
214 (self.emit_lint)(AttributeLint { id, span, kind: lint });
215 }
216
217 pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
218 self.emit_lint(
219 AttributeLintKind::UnusedDuplicate {
220 this: unused_span,
221 other: used_span,
222 warning: false,
223 },
224 unused_span,
225 )
226 }
227
228 pub(crate) fn warn_unused_duplicate_future_error(
229 &mut self,
230 used_span: Span,
231 unused_span: Span,
232 ) {
233 self.emit_lint(
234 AttributeLintKind::UnusedDuplicate {
235 this: unused_span,
236 other: used_span,
237 warning: true,
238 },
239 unused_span,
240 )
241 }
242}
243
244impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
245 pub(crate) fn unknown_key(
246 &self,
247 span: Span,
248 found: String,
249 options: &'static [&'static str],
250 ) -> ErrorGuaranteed {
251 self.emit_err(UnknownMetaItem { span, item: found, expected: options })
252 }
253
254 pub(crate) fn expected_string_literal(
259 &self,
260 span: Span,
261 actual_literal: Option<&MetaItemLit>,
262 ) -> ErrorGuaranteed {
263 self.emit_err(AttributeParseError {
264 span,
265 attr_span: self.attr_span,
266 template: self.template.clone(),
267 attribute: self.attr_path.clone(),
268 reason: AttributeParseErrorReason::ExpectedStringLiteral {
269 byte_string: actual_literal.and_then(|i| {
270 i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
271 }),
272 },
273 })
274 }
275
276 pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
277 self.emit_err(AttributeParseError {
278 span,
279 attr_span: self.attr_span,
280 template: self.template.clone(),
281 attribute: self.attr_path.clone(),
282 reason: AttributeParseErrorReason::ExpectedList,
283 })
284 }
285
286 pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
287 self.emit_err(AttributeParseError {
288 span: args_span,
289 attr_span: self.attr_span,
290 template: self.template.clone(),
291 attribute: self.attr_path.clone(),
292 reason: AttributeParseErrorReason::ExpectedNoArgs,
293 })
294 }
295
296 pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
299 self.emit_err(AttributeParseError {
300 span,
301 attr_span: self.attr_span,
302 template: self.template.clone(),
303 attribute: self.attr_path.clone(),
304 reason: AttributeParseErrorReason::ExpectedNameValue(name),
305 })
306 }
307
308 pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
310 self.emit_err(AttributeParseError {
311 span,
312 attr_span: self.attr_span,
313 template: self.template.clone(),
314 attribute: self.attr_path.clone(),
315 reason: AttributeParseErrorReason::DuplicateKey(key),
316 })
317 }
318
319 pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
322 self.emit_err(AttributeParseError {
323 span,
324 attr_span: self.attr_span,
325 template: self.template.clone(),
326 attribute: self.attr_path.clone(),
327 reason: AttributeParseErrorReason::UnexpectedLiteral,
328 })
329 }
330
331 pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
332 self.emit_err(AttributeParseError {
333 span,
334 attr_span: self.attr_span,
335 template: self.template.clone(),
336 attribute: self.attr_path.clone(),
337 reason: AttributeParseErrorReason::ExpectedSingleArgument,
338 })
339 }
340
341 pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
342 self.emit_err(AttributeParseError {
343 span,
344 attr_span: self.attr_span,
345 template: self.template.clone(),
346 attribute: self.attr_path.clone(),
347 reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
348 })
349 }
350
351 pub(crate) fn expected_specific_argument(
352 &self,
353 span: Span,
354 possibilities: Vec<&'static str>,
355 ) -> ErrorGuaranteed {
356 self.emit_err(AttributeParseError {
357 span,
358 attr_span: self.attr_span,
359 template: self.template.clone(),
360 attribute: self.attr_path.clone(),
361 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
362 possibilities,
363 strings: false,
364 },
365 })
366 }
367
368 pub(crate) fn expected_specific_argument_strings(
369 &self,
370 span: Span,
371 possibilities: Vec<&'static str>,
372 ) -> ErrorGuaranteed {
373 self.emit_err(AttributeParseError {
374 span,
375 attr_span: self.attr_span,
376 template: self.template.clone(),
377 attribute: self.attr_path.clone(),
378 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
379 possibilities,
380 strings: true,
381 },
382 })
383 }
384}
385
386impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
387 type Target = SharedContext<'f, 'sess, S>;
388
389 fn deref(&self) -> &Self::Target {
390 &self.shared
391 }
392}
393
394impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
395 fn deref_mut(&mut self) -> &mut Self::Target {
396 &mut self.shared
397 }
398}
399
400pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
405 pub(crate) cx: &'p mut AttributeParser<'sess, S>,
408 pub(crate) target_span: Span,
410 pub(crate) target_id: S::Id,
412
413 emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
414}
415
416pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
421 pub(crate) shared: SharedContext<'p, 'sess, S>,
422
423 pub(crate) all_attrs: &'p [PathParser<'p>],
430}
431
432impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
433 type Target = SharedContext<'p, 'sess, S>;
434
435 fn deref(&self) -> &Self::Target {
436 &self.shared
437 }
438}
439
440impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
441 fn deref_mut(&mut self) -> &mut Self::Target {
442 &mut self.shared
443 }
444}
445
446impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> {
447 type Target = AttributeParser<'sess, S>;
448
449 fn deref(&self) -> &Self::Target {
450 self.cx
451 }
452}
453
454impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> {
455 fn deref_mut(&mut self) -> &mut Self::Target {
456 self.cx
457 }
458}
459
460#[derive(PartialEq, Clone, Copy, Debug)]
461pub enum OmitDoc {
462 Lower,
463 Skip,
464}
465
466pub struct AttributeParser<'sess, S: Stage = Late> {
469 pub(crate) tools: Vec<Symbol>,
470 features: Option<&'sess Features>,
471 sess: &'sess Session,
472 stage: PhantomData<S>,
473
474 parse_only: Option<Symbol>,
478}
479
480impl<'sess> AttributeParser<'sess, Early> {
481 pub fn parse_limited(
496 sess: &'sess Session,
497 attrs: &[ast::Attribute],
498 sym: Symbol,
499 target_span: Span,
500 target_node_id: NodeId,
501 ) -> Option<Attribute> {
502 let mut p = Self {
503 features: None,
504 tools: Vec::new(),
505 parse_only: Some(sym),
506 sess,
507 stage: PhantomData,
508 };
509 let mut parsed = p.parse_attribute_list(
510 attrs,
511 target_span,
512 target_node_id,
513 OmitDoc::Skip,
514 std::convert::identity,
515 |_lint| {
516 panic!("can't emit lints here for now (nothing uses this atm)");
517 },
518 );
519 assert!(parsed.len() <= 1);
520
521 parsed.pop()
522 }
523}
524
525impl<'sess, S: Stage> AttributeParser<'sess, S> {
526 pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
527 Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
528 }
529
530 pub(crate) fn sess(&self) -> &'sess Session {
531 &self.sess
532 }
533
534 pub(crate) fn features(&self) -> &'sess Features {
535 self.features.expect("features not available at this point in the compiler")
536 }
537
538 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
539 self.sess().dcx()
540 }
541
542 pub fn parse_attribute_list(
547 &mut self,
548 attrs: &[ast::Attribute],
549 target_span: Span,
550 target_id: S::Id,
551 omit_doc: OmitDoc,
552
553 lower_span: impl Copy + Fn(Span) -> Span,
554 mut emit_lint: impl FnMut(AttributeLint<S::Id>),
555 ) -> Vec<Attribute> {
556 let mut attributes = Vec::new();
557 let mut attr_paths = Vec::new();
558
559 for attr in attrs {
560 if let Some(expected) = self.parse_only {
562 if !attr.has_name(expected) {
563 continue;
564 }
565 }
566
567 if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
573 continue;
574 }
575
576 match &attr.kind {
577 ast::AttrKind::DocComment(comment_kind, symbol) => {
578 if omit_doc == OmitDoc::Skip {
579 continue;
580 }
581
582 attributes.push(Attribute::Parsed(AttributeKind::DocComment {
583 style: attr.style,
584 kind: *comment_kind,
585 span: lower_span(attr.span),
586 comment: *symbol,
587 }))
588 }
589 ast::AttrKind::Normal(n) => {
601 attr_paths.push(PathParser::Ast(&n.item.path));
602
603 let parser = MetaItemParser::from_attr(n, self.dcx());
604 let path = parser.path();
605 let args = parser.args();
606 let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
607
608 if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
609 for (template, accept) in accepts {
610 let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
611 shared: SharedContext {
612 cx: self,
613 target_span,
614 target_id,
615 emit_lint: &mut emit_lint,
616 },
617 attr_span: lower_span(attr.span),
618 template,
619 attr_path: path.get_attribute_path(),
620 };
621
622 accept(&mut cx, args)
623 }
624 } else {
625 attributes.push(Attribute::Unparsed(Box::new(AttrItem {
641 path: AttrPath::from_ast(&n.item.path),
642 args: self.lower_attr_args(&n.item.args, lower_span),
643 id: HashIgnoredAttrId { attr_id: attr.id },
644 style: attr.style,
645 span: lower_span(attr.span),
646 })));
647 }
648 }
649 }
650 }
651
652 let mut parsed_attributes = Vec::new();
653 for f in &S::parsers().1 {
654 if let Some(attr) = f(&mut FinalizeContext {
655 shared: SharedContext {
656 cx: self,
657 target_span,
658 target_id,
659 emit_lint: &mut emit_lint,
660 },
661 all_attrs: &attr_paths,
662 }) {
663 parsed_attributes.push(Attribute::Parsed(attr));
664 }
665 }
666
667 attributes.extend(parsed_attributes);
668
669 attributes
670 }
671
672 fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
673 match args {
674 ast::AttrArgs::Empty => AttrArgs::Empty,
675 ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()),
676 ast::AttrArgs::Eq { eq_span, expr } => {
680 let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
683 && let Ok(lit) =
684 ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
685 {
686 lit
687 } else {
688 let guar = self.dcx().span_delayed_bug(
689 args.span().unwrap_or(DUMMY_SP),
690 "expr in place where literal is expected (builtin attr parsing)",
691 );
692 ast::MetaItemLit {
693 symbol: sym::dummy,
694 suffix: None,
695 kind: ast::LitKind::Err(guar),
696 span: DUMMY_SP,
697 }
698 };
699 AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
700 }
701 }
702 }
703}