Skip to content

Commit 565dce4

Browse files
authored
Unrolled build for #141746
Rollup merge of #141746 - Urgau:rework-doc_cfg-checks, r=GuillaumeGomez Rework `#[doc(cfg(..))]` checks as distinct pass in rustdoc This PR reworks how rustdoc calls `rustc_attr_parsing::cfg_matches` to be in a separate pass, instead of being wired-up in a ad-hoc way, which is causing problems in #138907 (comment). This un-does most part of #140894, but the result is IMO much cleaner, easier to reason about, and most importantly no longer interfears with #138907. r? `@GuillaumeGomez`
2 parents e6152cd + 9d0845a commit 565dce4

File tree

10 files changed

+127
-65
lines changed

10 files changed

+127
-65
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,12 @@ pub(crate) fn merge_attrs(
409409
} else {
410410
Attributes::from_hir(&both)
411411
},
412-
extract_cfg_from_attrs(both.iter(), cx.tcx, None, &cx.cache.hidden_cfg),
412+
extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg),
413413
)
414414
} else {
415415
(
416416
Attributes::from_hir(old_attrs),
417-
extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, None, &cx.cache.hidden_cfg),
417+
extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
418418
)
419419
}
420420
}

src/librustdoc/clean/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ fn generate_item_with_correct_attrs(
210210
Cow::Owned(attr) => attr,
211211
}),
212212
cx.tcx,
213-
def_id.as_local().map(|did| cx.tcx.local_def_id_to_hir_id(did)),
214213
&cx.cache.hidden_cfg,
215214
);
216215
let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);

src/librustdoc/clean/types.rs

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
1212
use rustc_hir::def::{CtorKind, DefKind, Res};
1313
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
1414
use rustc_hir::lang_items::LangItem;
15-
use rustc_hir::{BodyId, HirId, Mutability};
15+
use rustc_hir::{BodyId, Mutability};
1616
use rustc_index::IndexVec;
17-
use rustc_lint_defs::{BuiltinLintDiag, Lint};
1817
use rustc_metadata::rendered_const;
1918
use rustc_middle::span_bug;
2019
use rustc_middle::ty::fast_reject::SimplifiedType;
@@ -478,12 +477,7 @@ impl Item {
478477
name,
479478
kind,
480479
Attributes::from_hir(hir_attrs),
481-
extract_cfg_from_attrs(
482-
hir_attrs.iter(),
483-
cx.tcx,
484-
def_id.as_local().map(|did| cx.tcx.local_def_id_to_hir_id(did)),
485-
&cx.cache.hidden_cfg,
486-
),
480+
extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
487481
)
488482
}
489483

@@ -1039,7 +1033,6 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
10391033
pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
10401034
attrs: I,
10411035
tcx: TyCtxt<'_>,
1042-
hir_id: Option<HirId>,
10431036
hidden_cfg: &FxHashSet<Cfg>,
10441037
) -> Option<Arc<Cfg>> {
10451038
let doc_cfg_active = tcx.features().doc_cfg();
@@ -1064,42 +1057,10 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
10641057
if doc_cfg.peek().is_some() && doc_cfg_active {
10651058
let sess = tcx.sess;
10661059

1067-
struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, Option<HirId>);
1068-
1069-
impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> {
1070-
fn emit_span_lint(
1071-
&self,
1072-
sess: &Session,
1073-
lint: &'static Lint,
1074-
sp: rustc_span::Span,
1075-
builtin_diag: BuiltinLintDiag,
1076-
) {
1077-
if let Some(hir_id) = self.1 {
1078-
self.0.node_span_lint(lint, hir_id, sp, |diag| {
1079-
rustc_lint::decorate_builtin_lint(
1080-
sess,
1081-
Some(self.0),
1082-
builtin_diag,
1083-
diag,
1084-
)
1085-
});
1086-
} else {
1087-
// No HIR id. Probably in another crate. Don't lint.
1088-
}
1089-
}
1090-
}
1091-
10921060
doc_cfg.fold(Cfg::True, |mut cfg, item| {
10931061
if let Some(cfg_mi) =
10941062
item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
10951063
{
1096-
// The result is unused here but we can gate unstable predicates
1097-
rustc_attr_parsing::cfg_matches(
1098-
cfg_mi,
1099-
tcx.sess,
1100-
RustdocCfgMatchesLintEmitter(tcx, hir_id),
1101-
Some(tcx.features()),
1102-
);
11031064
match Cfg::parse(cfg_mi) {
11041065
Ok(new_cfg) => cfg &= new_cfg,
11051066
Err(e) => {

src/librustdoc/doctest/rust.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,9 @@ impl HirCollector<'_> {
116116
nested: F,
117117
) {
118118
let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
119-
if let Some(ref cfg) = extract_cfg_from_attrs(
120-
ast_attrs.iter(),
121-
self.tcx,
122-
Some(self.tcx.local_def_id_to_hir_id(def_id)),
123-
&FxHashSet::default(),
124-
) && !cfg.matches(&self.tcx.sess.psess)
119+
if let Some(ref cfg) =
120+
extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
121+
&& !cfg.matches(&self.tcx.sess.psess)
125122
{
126123
return;
127124
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use rustc_hir::HirId;
2+
use rustc_hir::def_id::LocalDefId;
3+
use rustc_middle::ty::TyCtxt;
4+
use rustc_span::sym;
5+
6+
use super::Pass;
7+
use crate::clean::{Attributes, Crate, Item};
8+
use crate::core::DocContext;
9+
use crate::visit::DocVisitor;
10+
11+
pub(crate) const CHECK_DOC_CFG: Pass = Pass {
12+
name: "check-doc-cfg",
13+
run: Some(check_doc_cfg),
14+
description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs",
15+
};
16+
17+
pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
18+
let mut checker = DocCfgChecker { cx };
19+
checker.visit_crate(&krate);
20+
krate
21+
}
22+
23+
struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId);
24+
25+
impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> {
26+
fn emit_span_lint(
27+
&self,
28+
sess: &rustc_session::Session,
29+
lint: &'static rustc_lint::Lint,
30+
sp: rustc_span::Span,
31+
builtin_diag: rustc_lint_defs::BuiltinLintDiag,
32+
) {
33+
self.0.node_span_lint(lint, self.1, sp, |diag| {
34+
rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag)
35+
});
36+
}
37+
}
38+
39+
struct DocCfgChecker<'a, 'tcx> {
40+
cx: &'a mut DocContext<'tcx>,
41+
}
42+
43+
impl DocCfgChecker<'_, '_> {
44+
fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) {
45+
let doc_cfgs = attrs
46+
.other_attrs
47+
.iter()
48+
.filter(|attr| attr.has_name(sym::doc))
49+
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
50+
.filter(|attr| attr.has_name(sym::cfg));
51+
52+
for doc_cfg in doc_cfgs {
53+
if let Some([cfg_mi]) = doc_cfg.meta_item_list() {
54+
let _ = rustc_attr_parsing::cfg_matches(
55+
cfg_mi,
56+
&self.cx.tcx.sess,
57+
RustdocCfgMatchesLintEmitter(
58+
self.cx.tcx,
59+
self.cx.tcx.local_def_id_to_hir_id(did),
60+
),
61+
Some(self.cx.tcx.features()),
62+
);
63+
}
64+
}
65+
}
66+
}
67+
68+
impl DocVisitor<'_> for DocCfgChecker<'_, '_> {
69+
fn visit_item(&mut self, item: &'_ Item) {
70+
if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) {
71+
self.check_attrs(&item.attrs, local_did);
72+
}
73+
74+
self.visit_item_recur(item);
75+
}
76+
}

src/librustdoc/passes/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
3232
mod check_doc_test_visibility;
3333
pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY;
3434

35+
mod check_doc_cfg;
36+
pub(crate) use self::check_doc_cfg::CHECK_DOC_CFG;
37+
3538
mod collect_trait_impls;
3639
pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS;
3740

@@ -72,6 +75,7 @@ pub(crate) enum Condition {
7275

7376
/// The full list of passes.
7477
pub(crate) const PASSES: &[Pass] = &[
78+
CHECK_DOC_CFG,
7579
CHECK_DOC_TEST_VISIBILITY,
7680
STRIP_ALIASED_NON_LOCAL,
7781
STRIP_HIDDEN,
@@ -89,6 +93,7 @@ pub(crate) const PASSES: &[Pass] = &[
8993
pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[
9094
ConditionalPass::always(COLLECT_TRAIT_IMPLS),
9195
ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
96+
ConditionalPass::always(CHECK_DOC_CFG),
9297
ConditionalPass::always(STRIP_ALIASED_NON_LOCAL),
9398
ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
9499
ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
warning: unexpected `cfg` condition name: `foo`
2-
--> $DIR/doc-cfg-check-cfg.rs:13:11
2+
--> $DIR/doc-cfg-check-cfg.rs:12:12
3+
|
4+
LL | #![doc(cfg(foo))]
5+
| ^^^
6+
|
7+
= help: to expect this configuration use `--check-cfg=cfg(foo)`
8+
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
9+
= note: `#[warn(unexpected_cfgs)]` on by default
10+
11+
warning: unexpected `cfg` condition name: `foo`
12+
--> $DIR/doc-cfg-check-cfg.rs:19:11
13+
|
14+
LL | #[doc(cfg(foo))]
15+
| ^^^
16+
|
17+
= help: to expect this configuration use `--check-cfg=cfg(foo)`
18+
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
19+
20+
warning: unexpected `cfg` condition name: `foo`
21+
--> $DIR/doc-cfg-check-cfg.rs:15:11
322
|
423
LL | #[doc(cfg(foo))]
524
| ^^^
625
|
726
= help: to expect this configuration use `--check-cfg=cfg(foo)`
827
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
9-
= note: `#[warn(unexpected_cfgs)]` on by default
1028

11-
warning: 1 warning emitted
29+
warning: 3 warnings emitted
1230

tests/rustdoc-ui/doc-cfg-check-cfg.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
//@[cfg_foo] compile-flags: --check-cfg cfg(foo)
1010

1111
#![feature(doc_cfg)]
12+
#![doc(cfg(foo))]
13+
//[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo`
1214

1315
#[doc(cfg(foo))]
1416
//[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo`
1517
pub fn foo() {}
1618

19+
#[doc(cfg(foo))]
20+
//[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo`
1721
pub mod module {
1822
#[allow(unexpected_cfgs)]
1923
#[doc(cfg(bar))]

tests/rustdoc-ui/doc-cfg.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ error: multiple `cfg` predicates are specified
1010
LL | #[doc(cfg(), cfg(foo, bar))]
1111
| ^^^
1212

13+
error: `cfg` predicate is not specified
14+
--> $DIR/doc-cfg.rs:9:7
15+
|
16+
LL | #[doc(cfg())]
17+
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
18+
19+
error: multiple `cfg` predicates are specified
20+
--> $DIR/doc-cfg.rs:10:16
21+
|
22+
LL | #[doc(cfg(foo, bar))]
23+
| ^^^
24+
1325
warning: unexpected `cfg` condition name: `foo`
1426
--> $DIR/doc-cfg.rs:6:11
1527
|
@@ -30,17 +42,5 @@ LL | #[doc(cfg(foo), cfg(bar))]
3042
= help: to expect this configuration use `--check-cfg=cfg(bar)`
3143
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
3244

33-
error: `cfg` predicate is not specified
34-
--> $DIR/doc-cfg.rs:9:7
35-
|
36-
LL | #[doc(cfg())]
37-
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
38-
39-
error: multiple `cfg` predicates are specified
40-
--> $DIR/doc-cfg.rs:10:16
41-
|
42-
LL | #[doc(cfg(foo, bar))]
43-
| ^^^
44-
4545
error: aborting due to 4 previous errors; 2 warnings emitted
4646

tests/rustdoc-ui/issues/issue-91713.stdout

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Available passes for running rustdoc:
2+
check-doc-cfg - checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs
23
check_doc_test_visibility - run various visibility-related lints on doctests
34
strip-aliased-non-local - strips all non-local private aliased items from the output
45
strip-hidden - strips all `#[doc(hidden)]` items from the output
@@ -14,6 +15,7 @@ calculate-doc-coverage - counts the number of items with and without documentati
1415
Default passes for rustdoc:
1516
collect-trait-impls
1617
check_doc_test_visibility
18+
check-doc-cfg
1719
strip-aliased-non-local
1820
strip-hidden (when not --document-hidden-items)
1921
strip-private (when not --document-private-items)

0 commit comments

Comments
 (0)