@@ -292,6 +292,11 @@ impl<'sess> AttributeParser<'sess> {
292292 mut emit_lint : impl FnMut ( LintId , MultiSpan , EmitAttribute ) ,
293293 ) -> Vec < Attribute > {
294294 let mut attributes = Vec :: new ( ) ;
295+ // We store the attributes we intend to discard at the end of this function in order to
296+ // check they are applied to the right target and error out if necessary. In practice, we
297+ // end up dropping only derive attributes and derive helpers, both being fully processed
298+ // at macro expansion.
299+ let mut dropped_attributes = Vec :: new ( ) ;
295300 let mut attr_paths: Vec < RefPathParser < ' _ > > = Vec :: new ( ) ;
296301 let mut early_parsed_state = EarlyParsedState :: default ( ) ;
297302
@@ -452,7 +457,19 @@ impl<'sess> AttributeParser<'sess> {
452457 self . check_invalid_crate_level_attr_item ( & attr, inner_span) ;
453458 }
454459
455- attributes. push ( Attribute :: Unparsed ( Box :: new ( attr) ) ) ;
460+ let attr = Attribute :: Unparsed ( Box :: new ( attr) ) ;
461+
462+ if self . sess . opts . actually_rustdoc
463+ || self . tools . is_some_and ( |t| t. iter ( ) . any ( |i| i. name == parts[ 0 ] ) )
464+ // FIXME: this can be removed once #155691 has been merged.
465+ // https://github.com/rust-lang/rust/pull/155691
466+ || [ sym:: allow, sym:: deny, sym:: expect, sym:: forbid, sym:: warn]
467+ . contains ( & parts[ 0 ] )
468+ {
469+ attributes. push ( attr) ;
470+ } else {
471+ dropped_attributes. push ( attr) ;
472+ }
456473 } ;
457474 }
458475 }
@@ -476,7 +493,7 @@ impl<'sess> AttributeParser<'sess> {
476493 }
477494
478495 if !matches ! ( self . should_emit, ShouldEmit :: Nothing ) && target == Target :: WherePredicate {
479- self . check_invalid_where_predicate_attrs ( attributes. iter ( ) ) ;
496+ self . check_invalid_where_predicate_attrs ( attributes. iter ( ) . chain ( & dropped_attributes ) ) ;
480497 }
481498
482499 attributes
0 commit comments