@@ -22,7 +22,7 @@ use rustc_session::lint::builtin::{
2222} ;
2323use rustc_session:: parse:: feature_err;
2424use rustc_span:: symbol:: { sym, Symbol } ;
25- use rustc_span:: { Span , DUMMY_SP } ;
25+ use rustc_span:: { MultiSpan , Span , DUMMY_SP } ;
2626
2727pub ( crate ) fn target_from_impl_item < ' tcx > (
2828 tcx : TyCtxt < ' tcx > ,
@@ -67,6 +67,7 @@ impl CheckAttrVisitor<'tcx> {
6767 item : Option < ItemLike < ' _ > > ,
6868 ) {
6969 let mut is_valid = true ;
70+ let mut specified_inline = None ;
7071 let attrs = self . tcx . hir ( ) . attrs ( hir_id) ;
7172 for attr in attrs {
7273 is_valid &= match attr. name_or_empty ( ) {
@@ -77,7 +78,7 @@ impl CheckAttrVisitor<'tcx> {
7778 sym:: track_caller => {
7879 self . check_track_caller ( hir_id, & attr. span , attrs, span, target)
7980 }
80- sym:: doc => self . check_doc_attrs ( attr, hir_id, target) ,
81+ sym:: doc => self . check_doc_attrs ( attr, hir_id, target, & mut specified_inline ) ,
8182 sym:: no_link => self . check_no_link ( hir_id, & attr, span, target) ,
8283 sym:: export_name => self . check_export_name ( hir_id, & attr, span, target) ,
8384 sym:: rustc_args_required_const => {
@@ -564,6 +565,60 @@ impl CheckAttrVisitor<'tcx> {
564565 true
565566 }
566567
568+ fn check_doc_inline (
569+ & self ,
570+ attr : & Attribute ,
571+ meta : & NestedMetaItem ,
572+ hir_id : HirId ,
573+ target : Target ,
574+ specified_inline : & mut Option < ( bool , Span ) > ,
575+ ) -> bool {
576+ if target == Target :: Use {
577+ let do_inline = meta. name_or_empty ( ) == sym:: inline;
578+ if let Some ( ( prev_inline, prev_span) ) = * specified_inline {
579+ if do_inline != prev_inline {
580+ let mut spans = MultiSpan :: from_spans ( vec ! [ prev_span, meta. span( ) ] ) ;
581+ spans. push_span_label ( prev_span, String :: from ( "this attribute..." ) ) ;
582+ spans. push_span_label (
583+ meta. span ( ) ,
584+ String :: from ( "...conflicts with this attribute" ) ,
585+ ) ;
586+ self . tcx
587+ . sess
588+ . struct_span_err ( spans, "conflicting doc inlining attributes" )
589+ . help ( "remove one of the conflicting attributes" )
590+ . emit ( ) ;
591+ return false ;
592+ }
593+ true
594+ } else {
595+ * specified_inline = Some ( ( do_inline, meta. span ( ) ) ) ;
596+ true
597+ }
598+ } else {
599+ self . tcx . struct_span_lint_hir (
600+ INVALID_DOC_ATTRIBUTES ,
601+ hir_id,
602+ meta. span ( ) ,
603+ |lint| {
604+ let mut err = lint. build (
605+ "this attribute can only be applied to a `use` item" ,
606+ ) ;
607+ err. span_label ( meta. span ( ) , "only applicable on `use` items" ) ;
608+ if attr. style == AttrStyle :: Outer {
609+ err. span_label (
610+ self . tcx . hir ( ) . span ( hir_id) ,
611+ "not a `use` item" ,
612+ ) ;
613+ }
614+ err. note ( "read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information" )
615+ . emit ( ) ;
616+ } ,
617+ ) ;
618+ false
619+ }
620+ }
621+
567622 fn check_attr_not_crate_level (
568623 & self ,
569624 meta : & NestedMetaItem ,
@@ -628,7 +683,13 @@ impl CheckAttrVisitor<'tcx> {
628683 true
629684 }
630685
631- fn check_doc_attrs ( & self , attr : & Attribute , hir_id : HirId , target : Target ) -> bool {
686+ fn check_doc_attrs (
687+ & self ,
688+ attr : & Attribute ,
689+ hir_id : HirId ,
690+ target : Target ,
691+ specified_inline : & mut Option < ( bool , Span ) > ,
692+ ) -> bool {
632693 let mut is_valid = true ;
633694
634695 if let Some ( list) = attr. meta ( ) . and_then ( |mi| mi. meta_item_list ( ) . map ( |l| l. to_vec ( ) ) ) {
@@ -661,33 +722,18 @@ impl CheckAttrVisitor<'tcx> {
661722 is_valid = false ;
662723 }
663724
664- sym:: inline | sym:: no_inline if target != Target :: Use => {
665- self . tcx . struct_span_lint_hir (
666- INVALID_DOC_ATTRIBUTES ,
725+ sym:: inline | sym:: no_inline
726+ if !self . check_doc_inline (
727+ & attr,
728+ & meta,
667729 hir_id,
668- meta. span ( ) ,
669- |lint| {
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 ( ) ;
682- } ,
683- ) ;
730+ target,
731+ specified_inline,
732+ ) =>
733+ {
684734 is_valid = false ;
685735 }
686736
687- sym:: inline | sym:: no_inline => {
688- // FIXME(#80275): conflicting inline attributes
689- }
690-
691737 // no_default_passes: deprecated
692738 // passes: deprecated
693739 // plugins: removed, but rustdoc warns about it itself
@@ -700,10 +746,12 @@ impl CheckAttrVisitor<'tcx> {
700746 | sym:: html_playground_url
701747 | sym:: html_root_url
702748 | sym:: include
749+ | sym:: inline
703750 | sym:: issue_tracker_base_url
704751 | sym:: keyword
705752 | sym:: masked
706753 | sym:: no_default_passes
754+ | sym:: no_inline
707755 | sym:: notable_trait
708756 | sym:: passes
709757 | sym:: plugins
0 commit comments