@@ -8,7 +8,7 @@ use rustc_middle::hir::map::Map;
88use rustc_middle:: ty:: query:: Providers ;
99use rustc_middle:: ty:: TyCtxt ;
1010
11- use rustc_ast:: { Attribute , Lit , LitKind , NestedMetaItem } ;
11+ use rustc_ast:: { AttrStyle , Attribute , Lit , LitKind , NestedMetaItem } ;
1212use rustc_errors:: { pluralize, struct_span_err, Applicability } ;
1313use rustc_hir as hir;
1414use rustc_hir:: def_id:: LocalDefId ;
@@ -564,7 +564,7 @@ impl CheckAttrVisitor<'tcx> {
564564 true
565565 }
566566
567- fn check_attr_crate_level (
567+ fn check_attr_not_crate_level (
568568 & self ,
569569 meta : & NestedMetaItem ,
570570 hir_id : HirId ,
@@ -586,6 +586,48 @@ impl CheckAttrVisitor<'tcx> {
586586 true
587587 }
588588
589+ fn check_attr_crate_level (
590+ & self ,
591+ attr : & Attribute ,
592+ meta : & NestedMetaItem ,
593+ hir_id : HirId ,
594+ ) -> bool {
595+ if hir_id != CRATE_HIR_ID {
596+ self . tcx . struct_span_lint_hir (
597+ INVALID_DOC_ATTRIBUTES ,
598+ hir_id,
599+ meta. span ( ) ,
600+ |lint| {
601+ let mut err = lint. build (
602+ "this attribute can only be applied at the crate level" ,
603+ ) ;
604+ if attr. style == AttrStyle :: Outer && self . tcx . hir ( ) . get_parent_item ( hir_id) == CRATE_HIR_ID {
605+ if let Ok ( mut src) =
606+ self . tcx . sess . source_map ( ) . span_to_snippet ( attr. span )
607+ {
608+ src. insert ( 1 , '!' ) ;
609+ err. span_suggestion_verbose (
610+ attr. span ,
611+ "to apply to the crate, use an inner attribute" ,
612+ src,
613+ Applicability :: MaybeIncorrect ,
614+ ) ;
615+ } else {
616+ err. span_help (
617+ attr. span ,
618+ "to apply to the crate, use an inner attribute" ,
619+ ) ;
620+ }
621+ }
622+ err. note ( "read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information" )
623+ . emit ( ) ;
624+ } ,
625+ ) ;
626+ return false ;
627+ }
628+ true
629+ }
630+
589631 fn check_doc_attrs ( & self , attr : & Attribute , hir_id : HirId , target : Target ) -> bool {
590632 let mut is_valid = true ;
591633
@@ -594,35 +636,58 @@ impl CheckAttrVisitor<'tcx> {
594636 if let Some ( i_meta) = meta. meta_item ( ) {
595637 match i_meta. name_or_empty ( ) {
596638 sym:: alias
597- if !self . check_attr_crate_level ( & meta, hir_id, "alias" )
639+ if !self . check_attr_not_crate_level ( & meta, hir_id, "alias" )
598640 || !self . check_doc_alias ( & meta, hir_id, target) =>
599641 {
600642 is_valid = false
601643 }
602644
603645 sym:: keyword
604- if !self . check_attr_crate_level ( & meta, hir_id, "keyword" )
646+ if !self . check_attr_not_crate_level ( & meta, hir_id, "keyword" )
605647 || !self . check_doc_keyword ( & meta, hir_id) =>
606648 {
607649 is_valid = false
608650 }
609651
610- sym:: test if CRATE_HIR_ID != hir_id => {
652+ sym:: html_favicon_url
653+ | sym:: html_logo_url
654+ | sym:: html_playground_url
655+ | sym:: issue_tracker_base_url
656+ | sym:: html_root_url
657+ | sym:: html_no_source
658+ | sym:: test
659+ if !self . check_attr_crate_level ( & attr, & meta, hir_id) =>
660+ {
661+ is_valid = false ;
662+ }
663+
664+ sym:: inline | sym:: no_inline if target != Target :: Use => {
611665 self . tcx . struct_span_lint_hir (
612666 INVALID_DOC_ATTRIBUTES ,
613667 hir_id,
614668 meta. span ( ) ,
615669 |lint| {
616- lint. build (
617- "`#![doc(test(...)]` is only allowed \
618- as a crate-level attribute",
619- )
620- . emit ( ) ;
670+ let mut err = lint. build (
671+ "this attribute can only be applied to a `use` item" ,
672+ ) ;
673+ err. span_label ( meta. span ( ) , "only applicable on `use` items" ) ;
674+ if attr. style == AttrStyle :: Outer {
675+ err. span_label (
676+ self . tcx . hir ( ) . span ( hir_id) ,
677+ "not a `use` item" ,
678+ ) ;
679+ }
680+ err. note ( "read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information" )
681+ . emit ( ) ;
621682 } ,
622683 ) ;
623684 is_valid = false ;
624685 }
625686
687+ sym:: inline | sym:: no_inline => {
688+ // FIXME(#80275): conflicting inline attributes
689+ }
690+
626691 // no_default_passes: deprecated
627692 // passes: deprecated
628693 // plugins: removed, but rustdoc warns about it itself
@@ -635,12 +700,10 @@ impl CheckAttrVisitor<'tcx> {
635700 | sym:: html_playground_url
636701 | sym:: html_root_url
637702 | sym:: include
638- | sym:: inline
639703 | sym:: issue_tracker_base_url
640704 | sym:: keyword
641705 | sym:: masked
642706 | sym:: no_default_passes
643- | sym:: no_inline
644707 | sym:: notable_trait
645708 | sym:: passes
646709 | sym:: plugins
0 commit comments