@@ -12,8 +12,8 @@ use rustc_ast::{AttrStyle, MetaItemLit, Safety};
1212use rustc_data_structures:: sync:: { DynSend , DynSync } ;
1313use rustc_errors:: { Diag , DiagCtxtHandle , Diagnostic , Level , MultiSpan } ;
1414use rustc_feature:: AttributeStability ;
15- use rustc_hir:: AttrPath ;
1615use rustc_hir:: attrs:: AttributeKind ;
16+ use rustc_hir:: { AttrPath , Attribute } ;
1717use rustc_parse:: parser:: Recovery ;
1818use rustc_session:: Session ;
1919use rustc_session:: lint:: { Lint , LintId } ;
@@ -93,7 +93,23 @@ pub(super) struct GroupTypeInnerAccept {
9393
9494pub ( crate ) type AcceptFn =
9595 Box < dyn for <' sess , ' a > Fn ( & mut AcceptContext < ' _ , ' sess > , & ArgParser ) + Send + Sync > ;
96- pub ( crate ) type FinalizeFn = fn ( & mut FinalizeContext < ' _ , ' _ > ) -> Option < AttributeKind > ;
96+ pub ( crate ) type FinalizeFn = fn ( & mut FinalizeContext < ' _ , ' _ > ) -> FinalizeOutput ;
97+
98+ /// A cross-attribute check that runs *after* all attributes on an item have been
99+ /// finalized, so it can inspect the fully parsed attributes via
100+ /// [`FinalizeContext::parsed_attrs`]. The [`Span`] is the span of the attribute the
101+ /// check is associated with, used for diagnostics.
102+ pub ( crate ) type FinalizeCheckFn = fn ( & FinalizeContext < ' _ , ' _ > , Span ) ;
103+
104+ /// The result of finalizing a single attribute parser.
105+ pub ( crate ) struct FinalizeOutput {
106+ /// The attribute the parser produced, if any.
107+ pub ( crate ) attr : Option < AttributeKind > ,
108+ /// A check to run once *all* attributes on the item have been finalized, together
109+ /// with the span it should be reported at. Deferred so that it can inspect the fully
110+ /// parsed attributes via [`FinalizeContext::parsed_attrs`].
111+ pub ( crate ) deferred_check : Option < ( FinalizeCheckFn , Span ) > ,
112+ }
97113
98114macro_rules! attribute_parsers {
99115 (
@@ -122,7 +138,11 @@ macro_rules! attribute_parsers {
122138 allowed_targets: <$names as crate :: attributes:: AttributeParser >:: ALLOWED_TARGETS ,
123139 finalizer: |cx| {
124140 let state = STATE_OBJECT . take( ) ;
125- state. finalize( cx)
141+ // Compute the deferred check (if any) before consuming
142+ // the state in `finalize`.
143+ let deferred_check = state. deferred_finalize_check( ) ;
144+ let attr = state. finalize( cx) ;
145+ FinalizeOutput { attr, deferred_check }
126146 }
127147 } ) ;
128148 }
@@ -777,6 +797,15 @@ pub(crate) struct FinalizeContext<'p, 'sess> {
777797 /// Usually, you should use normal attribute parsing logic instead,
778798 /// especially when making a *denylist* of other attributes.
779799 pub ( crate ) all_attrs : & ' p [ RefPathParser < ' p > ] ,
800+
801+ /// All attributes that have been parsed on this syntax node.
802+ ///
803+ /// Unlike [`all_attrs`](Self::all_attrs), which only contains the *paths* of the
804+ /// attributes, this contains the fully parsed attributes. It is only populated when
805+ /// running the deferred `finalize_check`s, which happen after all attributes on the
806+ /// item have been finalized. During finalization itself this is empty, since the
807+ /// attributes are not all available yet.
808+ pub ( crate ) parsed_attrs : & ' p [ Attribute ] ,
780809}
781810
782811impl < ' p , ' sess : ' p > Deref for FinalizeContext < ' p , ' sess > {
0 commit comments