Skip to content

Commit 0e8b824

Browse files
Add doc(auto_cfg) and doc(no_auto_cfg) attributes
1 parent c078410 commit 0e8b824

File tree

11 files changed

+113
-10
lines changed

11 files changed

+113
-10
lines changed

compiler/rustc_error_messages/locales/en-US/passes.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string litera
7575
passes_doc_alias_malformed =
7676
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
7777
78+
passes_doc_auto_cfg_malformed = `#![doc({$attr_str})]` attribute doesn't expect a value
79+
80+
passes_doc_no_auto_cfg_enabled_by_default = `doc(no_auto_cfg)` is enabled by default before the 2024 edition
81+
82+
passes_doc_auto_cfg_enabled_by_default = `doc(auto_cfg)` is enabled by default since the 2024 edition
83+
7884
passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules
7985
8086
passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules

compiler/rustc_passes/src/check_attr.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! item.
66
77
use 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};
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
1111
use rustc_expand::base::resolve_path;
@@ -25,6 +25,7 @@ use rustc_session::lint::builtin::{
2525
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
2626
};
2727
use rustc_session::parse::feature_err;
28+
use rustc_span::edition::Edition;
2829
use rustc_span::symbol::{kw, sym, Symbol};
2930
use rustc_span::{Span, DUMMY_SP};
3031
use 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 => {

compiler/rustc_passes/src/errors.rs

+16
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,22 @@ pub struct DocAliasMalformed {
189189
pub span: Span,
190190
}
191191

192+
#[derive(Diagnostic)]
193+
#[diag(passes::doc_auto_cfg_malformed)]
194+
pub struct DocAutoCfgMalformed<'a> {
195+
#[primary_span]
196+
pub span: Span,
197+
pub attr_str: &'a str,
198+
}
199+
200+
#[derive(LintDiagnostic)]
201+
#[diag(passes::doc_auto_cfg_enabled_by_default)]
202+
pub struct DocAutoCfgEnabledByDefault;
203+
204+
#[derive(LintDiagnostic)]
205+
#[diag(passes::doc_no_auto_cfg_enabled_by_default)]
206+
pub struct DocNoAutoCfgEnabledByDefault;
207+
192208
#[derive(Diagnostic)]
193209
#[diag(passes::doc_keyword_empty_mod)]
194210
pub struct DocKeywordEmptyMod {

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ symbols! {
408408
attr_literals,
409409
attributes,
410410
augmented_assignments,
411+
auto_cfg,
411412
auto_traits,
412413
automatically_derived,
413414
avx,
@@ -1009,6 +1010,7 @@ symbols! {
10091010
next,
10101011
nll,
10111012
no,
1013+
no_auto_cfg,
10121014
no_builtins,
10131015
no_core,
10141016
no_coverage,

src/librustdoc/clean/inline.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,13 @@ pub(crate) fn merge_attrs(
318318
} else {
319319
Attributes::from_ast(&both)
320320
},
321-
both.cfg(cx.tcx, &cx.cache.hidden_cfg),
321+
both.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active),
322322
)
323323
} else {
324-
(Attributes::from_ast(&old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
324+
(
325+
Attributes::from_ast(&old_attrs),
326+
old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active),
327+
)
325328
}
326329
}
327330

src/librustdoc/clean/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2112,7 +2112,7 @@ fn clean_extern_crate<'tcx>(
21122112
item_id: crate_def_id.into(),
21132113
visibility: clean_visibility(ty_vis),
21142114
kind: Box::new(ExternCrateItem { src: orig_name }),
2115-
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
2115+
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active),
21162116
}]
21172117
}
21182118

src/librustdoc/clean/types.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ impl Item {
463463
kind,
464464
Box::new(Attributes::from_ast(ast_attrs)),
465465
cx,
466-
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
466+
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active),
467467
)
468468
}
469469

@@ -838,7 +838,12 @@ pub(crate) trait AttributesExt {
838838

839839
fn inner_docs(&self) -> bool;
840840

841-
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
841+
fn cfg(
842+
&self,
843+
tcx: TyCtxt<'_>,
844+
hidden_cfg: &FxHashSet<Cfg>,
845+
doc_auto_cfg_active: bool,
846+
) -> Option<Arc<Cfg>>;
842847
}
843848

844849
impl AttributesExt for [ast::Attribute] {
@@ -864,10 +869,14 @@ impl AttributesExt for [ast::Attribute] {
864869
self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner)
865870
}
866871

867-
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
872+
fn cfg(
873+
&self,
874+
tcx: TyCtxt<'_>,
875+
hidden_cfg: &FxHashSet<Cfg>,
876+
doc_auto_cfg_active: bool,
877+
) -> Option<Arc<Cfg>> {
868878
let sess = tcx.sess;
869879
let doc_cfg_active = tcx.features().doc_cfg;
870-
let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
871880

872881
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
873882
let mut iter = it.into_iter();

src/librustdoc/doctest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
12101210
nested: F,
12111211
) {
12121212
let ast_attrs = self.tcx.hir().attrs(hir_id);
1213-
if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
1213+
if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default(), false) {
12141214
if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
12151215
return;
12161216
}

src/librustdoc/formats/cache.rs

+2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ pub(crate) struct Cache {
121121
pub(crate) intra_doc_links: FxHashMap<ItemId, Vec<clean::ItemLink>>,
122122
/// Cfg that have been hidden via #![doc(cfg_hide(...))]
123123
pub(crate) hidden_cfg: FxHashSet<clean::cfg::Cfg>,
124+
/// Whether or not the `#![doc(auto_cfg)]` attribute was used.
125+
pub(crate) doc_auto_cfg_active: bool,
124126
}
125127

126128
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.

src/librustdoc/html/render/print_item.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,11 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
351351
let import_item = clean::Item {
352352
item_id: import_def_id.into(),
353353
attrs: import_attrs,
354-
cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg),
354+
cfg: ast_attrs.cfg(
355+
cx.tcx(),
356+
&cx.cache().hidden_cfg,
357+
cx.cache().doc_auto_cfg_active,
358+
),
355359
..myitem.clone()
356360
};
357361

src/librustdoc/visit_ast.rs

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_hir::CRATE_HIR_ID;
1010
use rustc_middle::middle::privacy::AccessLevel;
1111
use rustc_middle::ty::TyCtxt;
1212
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
13+
use rustc_span::edition::Edition;
1314
use rustc_span::symbol::{kw, sym, Symbol};
1415
use rustc_span::Span;
1516

@@ -146,6 +147,22 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
146147
.into_iter(),
147148
)
148149
.collect();
150+
// This feature is enabled by default starting the 2024 edition.
151+
self.cx.cache.doc_auto_cfg_active = self.cx.tcx.sess.edition() > Edition::Edition2021;
152+
if let Some(attr) = self
153+
.cx
154+
.tcx
155+
.hir()
156+
.attrs(CRATE_HIR_ID)
157+
.iter()
158+
.filter(|attr| attr.has_name(sym::doc))
159+
.flat_map(|attr| attr.meta_item_list().into_iter().flatten())
160+
.find(|attr| attr.has_name(sym::auto_cfg) || attr.has_name(sym::auto_cfg))
161+
{
162+
// If we find one of the two attributes, we update the default value of
163+
// `doc_auto_cfg_active`.
164+
self.cx.cache.doc_auto_cfg_active = attr.has_name(sym::auto_cfg);
165+
}
149166

150167
self.cx.cache.exact_paths = self.exact_paths;
151168
top_level_module

0 commit comments

Comments
 (0)