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, TargetFeatureParser,
20 TrackCallerParser, UsedParser,
21};
22use crate::attributes::confusables::ConfusablesParser;
23use crate::attributes::deprecation::DeprecationParser;
24use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
25use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser};
26use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTransparentParser};
27use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
28use crate::attributes::must_use::MustUseParser;
29use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
30use crate::attributes::non_exhaustive::NonExhaustiveParser;
31use crate::attributes::path::PathParser as PathAttributeParser;
32use crate::attributes::repr::{AlignParser, ReprParser};
33use crate::attributes::rustc_internal::{
34 RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
35 RustcObjectLifetimeDefaultParser,
36};
37use crate::attributes::semantics::MayDangleParser;
38use crate::attributes::stability::{
39 BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
40};
41use crate::attributes::test_attrs::IgnoreParser;
42use crate::attributes::traits::SkipDuringMethodDispatchParser;
43use crate::attributes::transparency::TransparencyParser;
44use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
45use crate::parser::{ArgParser, MetaItemParser, PathParser};
46use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
47
48macro_rules! group_type {
49 ($stage: ty) => {
50 LazyLock<(
51 BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
52 Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
53 )>
54 };
55}
56
57macro_rules! attribute_parsers {
58 (
59 pub(crate) static $name: ident = [$($names: ty),* $(,)?];
60 ) => {
61 mod early {
62 use super::*;
63 type Combine<T> = super::Combine<T, Early>;
64 type Single<T> = super::Single<T, Early>;
65 type WithoutArgs<T> = super::WithoutArgs<T, Early>;
66
67 attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
68 }
69 mod late {
70 use super::*;
71 type Combine<T> = super::Combine<T, Late>;
72 type Single<T> = super::Single<T, Late>;
73 type WithoutArgs<T> = super::WithoutArgs<T, Late>;
74
75 attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
76 }
77 };
78 (
79 @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
80 ) => {
81 pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
82 let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
83 let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
84 $(
85 {
86 thread_local! {
87 static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
88 };
89
90 for (path, template, accept_fn) in <$names>::ATTRIBUTES {
91 accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
92 STATE_OBJECT.with_borrow_mut(|s| {
93 accept_fn(s, cx, args)
94 })
95 })));
96 }
97
98 finalizes.push(Box::new(|cx| {
99 let state = STATE_OBJECT.take();
100 state.finalize(cx)
101 }));
102 }
103 )*
104
105 (accepts, finalizes)
106 });
107 };
108}
109attribute_parsers!(
110 pub(crate) static ATTRIBUTE_PARSERS = [
111 AlignParser,
113 BodyStabilityParser,
114 ConfusablesParser,
115 ConstStabilityParser,
116 NakedParser,
117 StabilityParser,
118 UsedParser,
119 Combine<AllowConstFnUnstableParser>,
123 Combine<AllowInternalUnstableParser>,
124 Combine<ReprParser>,
125 Combine<TargetFeatureParser>,
126 Single<DeprecationParser>,
130 Single<ExportNameParser>,
131 Single<IgnoreParser>,
132 Single<InlineParser>,
133 Single<LinkNameParser>,
134 Single<LinkSectionParser>,
135 Single<MustUseParser>,
136 Single<OptimizeParser>,
137 Single<PathAttributeParser>,
138 Single<RustcForceInlineParser>,
139 Single<RustcLayoutScalarValidRangeEnd>,
140 Single<RustcLayoutScalarValidRangeStart>,
141 Single<RustcObjectLifetimeDefaultParser>,
142 Single<SkipDuringMethodDispatchParser>,
143 Single<TransparencyParser>,
144 Single<WithoutArgs<AsPtrParser>>,
145 Single<WithoutArgs<ColdParser>>,
146 Single<WithoutArgs<ConstContinueParser>>,
147 Single<WithoutArgs<ConstStabilityIndirectParser>>,
148 Single<WithoutArgs<LoopMatchParser>>,
149 Single<WithoutArgs<MayDangleParser>>,
150 Single<WithoutArgs<NoImplicitPreludeParser>>,
151 Single<WithoutArgs<NoMangleParser>>,
152 Single<WithoutArgs<NonExhaustiveParser>>,
153 Single<WithoutArgs<PassByValueParser>>,
154 Single<WithoutArgs<PubTransparentParser>>,
155 Single<WithoutArgs<TrackCallerParser>>,
156 ];
158);
159
160mod private {
161 pub trait Sealed {}
162 impl Sealed for super::Early {}
163 impl Sealed for super::Late {}
164}
165
166#[allow(private_interfaces)]
168pub trait Stage: Sized + 'static + Sealed {
169 type Id: Copy;
170 const SHOULD_EMIT_LINTS: bool;
171
172 fn parsers() -> &'static group_type!(Self);
173
174 fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
175}
176
177#[allow(private_interfaces)]
179impl Stage for Early {
180 type Id = NodeId;
181 const SHOULD_EMIT_LINTS: bool = false;
182
183 fn parsers() -> &'static group_type!(Self) {
184 &early::ATTRIBUTE_PARSERS
185 }
186 fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
187 sess.dcx().create_err(diag).delay_as_bug()
188 }
189}
190
191#[allow(private_interfaces)]
193impl Stage for Late {
194 type Id = HirId;
195 const SHOULD_EMIT_LINTS: bool = true;
196
197 fn parsers() -> &'static group_type!(Self) {
198 &late::ATTRIBUTE_PARSERS
199 }
200 fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
201 tcx.dcx().emit_err(diag)
202 }
203}
204
205pub struct Early;
207pub struct Late;
209
210pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
214 pub(crate) shared: SharedContext<'f, 'sess, S>,
215 pub(crate) attr_span: Span,
217
218 pub(crate) template: &'f AttributeTemplate,
222
223 pub(crate) attr_path: AttrPath,
225}
226
227impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
228 pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
229 S::emit_err(&self.sess, diag)
230 }
231
232 pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
236 if !S::SHOULD_EMIT_LINTS {
237 return;
238 }
239 let id = self.target_id;
240 (self.emit_lint)(AttributeLint { id, span, kind: lint });
241 }
242
243 pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
244 self.emit_lint(
245 AttributeLintKind::UnusedDuplicate {
246 this: unused_span,
247 other: used_span,
248 warning: false,
249 },
250 unused_span,
251 )
252 }
253
254 pub(crate) fn warn_unused_duplicate_future_error(
255 &mut self,
256 used_span: Span,
257 unused_span: Span,
258 ) {
259 self.emit_lint(
260 AttributeLintKind::UnusedDuplicate {
261 this: unused_span,
262 other: used_span,
263 warning: true,
264 },
265 unused_span,
266 )
267 }
268}
269
270impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
271 pub(crate) fn unknown_key(
272 &self,
273 span: Span,
274 found: String,
275 options: &'static [&'static str],
276 ) -> ErrorGuaranteed {
277 self.emit_err(UnknownMetaItem { span, item: found, expected: options })
278 }
279
280 pub(crate) fn expected_string_literal(
285 &self,
286 span: Span,
287 actual_literal: Option<&MetaItemLit>,
288 ) -> ErrorGuaranteed {
289 self.emit_err(AttributeParseError {
290 span,
291 attr_span: self.attr_span,
292 template: self.template.clone(),
293 attribute: self.attr_path.clone(),
294 reason: AttributeParseErrorReason::ExpectedStringLiteral {
295 byte_string: actual_literal.and_then(|i| {
296 i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
297 }),
298 },
299 })
300 }
301
302 pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
303 self.emit_err(AttributeParseError {
304 span,
305 attr_span: self.attr_span,
306 template: self.template.clone(),
307 attribute: self.attr_path.clone(),
308 reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
309 })
310 }
311
312 pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
313 self.emit_err(AttributeParseError {
314 span,
315 attr_span: self.attr_span,
316 template: self.template.clone(),
317 attribute: self.attr_path.clone(),
318 reason: AttributeParseErrorReason::ExpectedList,
319 })
320 }
321
322 pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
323 self.emit_err(AttributeParseError {
324 span: args_span,
325 attr_span: self.attr_span,
326 template: self.template.clone(),
327 attribute: self.attr_path.clone(),
328 reason: AttributeParseErrorReason::ExpectedNoArgs,
329 })
330 }
331
332 pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
335 self.emit_err(AttributeParseError {
336 span,
337 attr_span: self.attr_span,
338 template: self.template.clone(),
339 attribute: self.attr_path.clone(),
340 reason: AttributeParseErrorReason::ExpectedNameValue(name),
341 })
342 }
343
344 pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
346 self.emit_err(AttributeParseError {
347 span,
348 attr_span: self.attr_span,
349 template: self.template.clone(),
350 attribute: self.attr_path.clone(),
351 reason: AttributeParseErrorReason::DuplicateKey(key),
352 })
353 }
354
355 pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
358 self.emit_err(AttributeParseError {
359 span,
360 attr_span: self.attr_span,
361 template: self.template.clone(),
362 attribute: self.attr_path.clone(),
363 reason: AttributeParseErrorReason::UnexpectedLiteral,
364 })
365 }
366
367 pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
368 self.emit_err(AttributeParseError {
369 span,
370 attr_span: self.attr_span,
371 template: self.template.clone(),
372 attribute: self.attr_path.clone(),
373 reason: AttributeParseErrorReason::ExpectedSingleArgument,
374 })
375 }
376
377 pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
378 self.emit_err(AttributeParseError {
379 span,
380 attr_span: self.attr_span,
381 template: self.template.clone(),
382 attribute: self.attr_path.clone(),
383 reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
384 })
385 }
386
387 pub(crate) fn expected_specific_argument(
388 &self,
389 span: Span,
390 possibilities: Vec<&'static str>,
391 ) -> ErrorGuaranteed {
392 self.emit_err(AttributeParseError {
393 span,
394 attr_span: self.attr_span,
395 template: self.template.clone(),
396 attribute: self.attr_path.clone(),
397 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
398 possibilities,
399 strings: false,
400 },
401 })
402 }
403
404 pub(crate) fn expected_specific_argument_strings(
405 &self,
406 span: Span,
407 possibilities: Vec<&'static str>,
408 ) -> ErrorGuaranteed {
409 self.emit_err(AttributeParseError {
410 span,
411 attr_span: self.attr_span,
412 template: self.template.clone(),
413 attribute: self.attr_path.clone(),
414 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
415 possibilities,
416 strings: true,
417 },
418 })
419 }
420
421 pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
422 self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span);
423 }
424}
425
426impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
427 type Target = SharedContext<'f, 'sess, S>;
428
429 fn deref(&self) -> &Self::Target {
430 &self.shared
431 }
432}
433
434impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
435 fn deref_mut(&mut self) -> &mut Self::Target {
436 &mut self.shared
437 }
438}
439
440pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
445 pub(crate) cx: &'p mut AttributeParser<'sess, S>,
448 pub(crate) target_span: Span,
450 pub(crate) target_id: S::Id,
452
453 emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
454}
455
456pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
461 pub(crate) shared: SharedContext<'p, 'sess, S>,
462
463 pub(crate) all_attrs: &'p [PathParser<'p>],
470}
471
472impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
473 type Target = SharedContext<'p, 'sess, S>;
474
475 fn deref(&self) -> &Self::Target {
476 &self.shared
477 }
478}
479
480impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
481 fn deref_mut(&mut self) -> &mut Self::Target {
482 &mut self.shared
483 }
484}
485
486impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> {
487 type Target = AttributeParser<'sess, S>;
488
489 fn deref(&self) -> &Self::Target {
490 self.cx
491 }
492}
493
494impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> {
495 fn deref_mut(&mut self) -> &mut Self::Target {
496 self.cx
497 }
498}
499
500#[derive(PartialEq, Clone, Copy, Debug)]
501pub enum OmitDoc {
502 Lower,
503 Skip,
504}
505
506pub struct AttributeParser<'sess, S: Stage = Late> {
509 pub(crate) tools: Vec<Symbol>,
510 features: Option<&'sess Features>,
511 sess: &'sess Session,
512 stage: PhantomData<S>,
513
514 parse_only: Option<Symbol>,
518}
519
520impl<'sess> AttributeParser<'sess, Early> {
521 pub fn parse_limited(
536 sess: &'sess Session,
537 attrs: &[ast::Attribute],
538 sym: Symbol,
539 target_span: Span,
540 target_node_id: NodeId,
541 ) -> Option<Attribute> {
542 let mut p = Self {
543 features: None,
544 tools: Vec::new(),
545 parse_only: Some(sym),
546 sess,
547 stage: PhantomData,
548 };
549 let mut parsed = p.parse_attribute_list(
550 attrs,
551 target_span,
552 target_node_id,
553 OmitDoc::Skip,
554 std::convert::identity,
555 |_lint| {
556 panic!("can't emit lints here for now (nothing uses this atm)");
557 },
558 );
559 assert!(parsed.len() <= 1);
560
561 parsed.pop()
562 }
563}
564
565impl<'sess, S: Stage> AttributeParser<'sess, S> {
566 pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
567 Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
568 }
569
570 pub(crate) fn sess(&self) -> &'sess Session {
571 &self.sess
572 }
573
574 pub(crate) fn features(&self) -> &'sess Features {
575 self.features.expect("features not available at this point in the compiler")
576 }
577
578 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
579 self.sess().dcx()
580 }
581
582 pub fn parse_attribute_list(
587 &mut self,
588 attrs: &[ast::Attribute],
589 target_span: Span,
590 target_id: S::Id,
591 omit_doc: OmitDoc,
592
593 lower_span: impl Copy + Fn(Span) -> Span,
594 mut emit_lint: impl FnMut(AttributeLint<S::Id>),
595 ) -> Vec<Attribute> {
596 let mut attributes = Vec::new();
597 let mut attr_paths = Vec::new();
598
599 for attr in attrs {
600 if let Some(expected) = self.parse_only {
602 if !attr.has_name(expected) {
603 continue;
604 }
605 }
606
607 if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
613 continue;
614 }
615
616 match &attr.kind {
617 ast::AttrKind::DocComment(comment_kind, symbol) => {
618 if omit_doc == OmitDoc::Skip {
619 continue;
620 }
621
622 attributes.push(Attribute::Parsed(AttributeKind::DocComment {
623 style: attr.style,
624 kind: *comment_kind,
625 span: lower_span(attr.span),
626 comment: *symbol,
627 }))
628 }
629 ast::AttrKind::Normal(n) => {
641 attr_paths.push(PathParser::Ast(&n.item.path));
642
643 let parser = MetaItemParser::from_attr(n, self.dcx());
644 let path = parser.path();
645 let args = parser.args();
646 let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
647
648 if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
649 for (template, accept) in accepts {
650 let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
651 shared: SharedContext {
652 cx: self,
653 target_span,
654 target_id,
655 emit_lint: &mut emit_lint,
656 },
657 attr_span: lower_span(attr.span),
658 template,
659 attr_path: path.get_attribute_path(),
660 };
661
662 accept(&mut cx, args)
663 }
664 } else {
665 attributes.push(Attribute::Unparsed(Box::new(AttrItem {
681 path: AttrPath::from_ast(&n.item.path),
682 args: self.lower_attr_args(&n.item.args, lower_span),
683 id: HashIgnoredAttrId { attr_id: attr.id },
684 style: attr.style,
685 span: lower_span(attr.span),
686 })));
687 }
688 }
689 }
690 }
691
692 let mut parsed_attributes = Vec::new();
693 for f in &S::parsers().1 {
694 if let Some(attr) = f(&mut FinalizeContext {
695 shared: SharedContext {
696 cx: self,
697 target_span,
698 target_id,
699 emit_lint: &mut emit_lint,
700 },
701 all_attrs: &attr_paths,
702 }) {
703 parsed_attributes.push(Attribute::Parsed(attr));
704 }
705 }
706
707 attributes.extend(parsed_attributes);
708
709 attributes
710 }
711
712 fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
713 match args {
714 ast::AttrArgs::Empty => AttrArgs::Empty,
715 ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()),
716 ast::AttrArgs::Eq { eq_span, expr } => {
720 let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
723 && let Ok(lit) =
724 ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
725 {
726 lit
727 } else {
728 let guar = self.dcx().span_delayed_bug(
729 args.span().unwrap_or(DUMMY_SP),
730 "expr in place where literal is expected (builtin attr parsing)",
731 );
732 ast::MetaItemLit {
733 symbol: sym::dummy,
734 suffix: None,
735 kind: ast::LitKind::Err(guar),
736 span: DUMMY_SP,
737 }
738 };
739 AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
740 }
741 }
742 }
743}