55//! item.
66
77use crate :: errors;
8- use rustc_ast:: { ast, AttrStyle , Attribute , Lit , LitKind , MetaItemKind , NestedMetaItem } ;
8+ use rustc_ast:: { ast, AttrStyle , Attribute , Lit , LitKind , MetaItem , MetaItemKind , NestedMetaItem } ;
99use rustc_data_structures:: fx:: FxHashMap ;
1010use rustc_errors:: { fluent, struct_span_err, Applicability , MultiSpan } ;
1111use rustc_expand:: base:: resolve_path;
@@ -25,6 +25,7 @@ use rustc_session::lint::builtin::{
2525 CONFLICTING_REPR_HINTS , INVALID_DOC_ATTRIBUTES , UNUSED_ATTRIBUTES ,
2626} ;
2727use rustc_session:: parse:: feature_err;
28+ use rustc_span:: edition:: Edition ;
2829use rustc_span:: symbol:: { kw, sym, Symbol } ;
2930use rustc_span:: { Span , DUMMY_SP } ;
3031use rustc_target:: spec:: abi:: Abi ;
@@ -945,6 +946,40 @@ impl CheckAttrVisitor<'_> {
945946 is_valid
946947 }
947948
949+ /// Checks that `doc(auto_cfg)` is valid (i.e. no value) and warn if it's used whereas the
950+ /// "equivalent feature" is already enabled.
951+ fn check_auto_cfg ( & self , meta : & MetaItem , hir_id : HirId ) -> bool {
952+ let name = meta. name_or_empty ( ) ;
953+ let mut is_valid = true ;
954+ if !meta. is_word ( ) {
955+ self . tcx
956+ . sess
957+ . emit_err ( errors:: DocAutoCfgMalformed { span : meta. span , attr_str : name. as_str ( ) } ) ;
958+ is_valid = false ;
959+ } else if name == sym:: no_auto_cfg {
960+ if self . tcx . sess . edition ( ) < Edition :: Edition2024 {
961+ self . tcx . emit_spanned_lint (
962+ UNUSED_ATTRIBUTES ,
963+ hir_id,
964+ meta. span ,
965+ errors:: DocNoAutoCfgEnabledByDefault ,
966+ ) ;
967+ is_valid = false ;
968+ }
969+ } else {
970+ if self . tcx . sess . edition ( ) > Edition :: Edition2021 {
971+ self . tcx . emit_spanned_lint (
972+ UNUSED_ATTRIBUTES ,
973+ hir_id,
974+ meta. span ,
975+ errors:: DocAutoCfgEnabledByDefault ,
976+ ) ;
977+ is_valid = false ;
978+ }
979+ }
980+ is_valid
981+ }
982+
948983 /// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
949984 ///
950985 /// `specified_inline` should be initialized to `None` and kept for the scope
@@ -993,6 +1028,8 @@ impl CheckAttrVisitor<'_> {
9931028 | sym:: html_root_url
9941029 | sym:: html_no_source
9951030 | sym:: test
1031+ | sym:: auto_cfg
1032+ | sym:: no_auto_cfg
9961033 if !self . check_attr_crate_level ( attr, meta, hir_id) =>
9971034 {
9981035 is_valid = false ;
@@ -1010,6 +1047,11 @@ impl CheckAttrVisitor<'_> {
10101047 is_valid = false ;
10111048 }
10121049
1050+ sym:: auto_cfg | sym:: no_auto_cfg
1051+ if !self . check_auto_cfg ( i_meta, hir_id) => {
1052+ is_valid = false ;
1053+ }
1054+
10131055 // no_default_passes: deprecated
10141056 // passes: deprecated
10151057 // plugins: removed, but rustdoc warns about it itself
@@ -1031,6 +1073,8 @@ impl CheckAttrVisitor<'_> {
10311073 | sym:: notable_trait
10321074 | sym:: passes
10331075 | sym:: plugins
1076+ | sym:: auto_cfg
1077+ | sym:: no_auto_cfg
10341078 | sym:: fake_variadic => { }
10351079
10361080 sym:: test => {
0 commit comments