From 64aaeacd7168ae1995fed60974142db14e246840 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 22:27:28 +0100 Subject: [PATCH] Update to new API, allowing to remove `check_doc_cfg.rs` file from librustdoc --- .../src/attributes/cfg_old.rs | 1 - .../rustc_attr_parsing/src/attributes/doc.rs | 11 ++- .../rustc_hir/src/attrs/data_structures.rs | 11 +-- library/std/build.rs | 3 + src/librustdoc/clean/cfg.rs | 43 ++++------- src/librustdoc/clean/cfg/tests.rs | 11 +-- src/librustdoc/lib.rs | 1 - src/librustdoc/passes/check_doc_cfg.rs | 72 ------------------- src/librustdoc/passes/mod.rs | 5 -- tests/rustdoc-ui/doc-cfg-2.rs | 2 + tests/rustdoc-ui/doc-cfg-2.stderr | 20 +++++- .../doc-cfg-check-cfg.cfg_empty.stderr | 12 ++-- tests/rustdoc-ui/issues/issue-91713.stdout | 2 - 13 files changed, 59 insertions(+), 135 deletions(-) delete mode 100644 src/librustdoc/passes/check_doc_cfg.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 29be000d476d..acb234480d5d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -2,7 +2,6 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Nod use rustc_ast_pretty::pprust; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::RustcVersion; -use rustc_hir::lints::AttributeLintKind; use rustc_session::Session; use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index a26f22c4455d..ccb6a873fb12 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -294,7 +294,7 @@ impl DocParser { cx.expected_identifier(sub_item.path().span()); continue; }; - if let Ok(CfgEntry::NameValue { name, name_span, value, .. }) = + if let Ok(CfgEntry::NameValue { name, value, .. }) = super::cfg::parse_name_value( name, sub_item.path().span(), @@ -303,7 +303,14 @@ impl DocParser { cx, ) { - cfg_hide_show.values.push(CfgInfo { name, name_span, value }) + cfg_hide_show.values.push(CfgInfo { + name, + name_span: sub_item.path().span(), + // If `value` is `Some`, `a.name_value()` will always return + // `Some` as well. + value: value + .map(|v| (v, a.name_value().unwrap().value_span)), + }) } } _ => { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e4a55bf39333..b7f8be3ec88f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -218,14 +218,7 @@ impl CfgEntry { ( Self::NameValue { name: name1, value: value1, .. }, Self::NameValue { name: name2, value: value2, .. }, - ) => { - name1 == name2 - && match (value1, value2) { - (Some((a, _)), Some((b, _))) => a == b, - (None, None) => true, - _ => false, - } - } + ) => name1 == name2 && value1 == value2, (Self::Version(a, _), Self::Version(b, _)) => a == b, _ => false, } @@ -257,7 +250,7 @@ impl fmt::Display for CfgEntry { match value { // We use `as_str` and debug display to have characters escaped and `"` // characters surrounding the string. - Some((value, _)) => write!(f, "{name} = {:?}", value.as_str()), + Some(value) => write!(f, "{name} = {:?}", value.as_str()), None => write!(f, "{name}"), } } diff --git a/library/std/build.rs b/library/std/build.rs index bee28e88491d..c0a6e30b3808 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -13,6 +13,9 @@ fn main() { println!("cargo:rustc-cfg=netbsd10"); } + // Needed for `#![doc(auto_cfg(hide(no_global_oom_handling)))]` attribute. + println!("cargo::rustc-check-cfg=cfg(no_global_oom_handling)"); + println!("cargo:rustc-check-cfg=cfg(restricted_std)"); if target_os == "linux" || target_os == "android" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 1413f7f56c96..97a60c5a5098 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -140,12 +140,7 @@ impl Cfg { if exclude.contains(&NameValueCfg::new(name)) { Ok(None) } else { - Ok(Some(Cfg(CfgEntry::NameValue { - name, - value: None, - name_span: DUMMY_SP, - span: DUMMY_SP, - }))) + Ok(Some(Cfg(CfgEntry::NameValue { name, value: None, span: DUMMY_SP }))) } } MetaItemKind::NameValue(ref lit) => match lit.kind { @@ -155,8 +150,7 @@ impl Cfg { } else { Ok(Some(Cfg(CfgEntry::NameValue { name, - value: Some((value, DUMMY_SP)), - name_span: DUMMY_SP, + value: Some(value), span: DUMMY_SP, }))) } @@ -226,9 +220,7 @@ impl Cfg { CfgEntry::Any(sub_cfgs, _) => { sub_cfgs.iter().any(|sub_cfg| cfg_matches(sub_cfg, psess)) } - CfgEntry::NameValue { name, value, .. } => { - psess.config.contains(&(*name, value.clone().map(|(s, _)| s))) - } + CfgEntry::NameValue { name, value, .. } => psess.config.contains(&(*name, *value)), CfgEntry::Version(..) => { // FIXME: should be handled. false @@ -497,7 +489,7 @@ impl Display<'_> { sub_cfgs .iter() .map(|sub_cfg| { - if let CfgEntry::NameValue { value: Some((feat, _)), .. } = sub_cfg + if let CfgEntry::NameValue { value: Some(feat), .. } = sub_cfg && short_longhand { Either::Left(self.code_wrappers().wrap(feat)) @@ -557,7 +549,7 @@ impl fmt::Display for Display<'_> { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", (sym::debug_assertions, None) => "debug-assertions enabled", - (sym::target_os, Some((os, _))) => match os.as_str() { + (sym::target_os, Some(os)) => match os.as_str() { "android" => "Android", "cygwin" => "Cygwin", "dragonfly" => "DragonFly BSD", @@ -582,7 +574,7 @@ impl fmt::Display for Display<'_> { "visionos" => "visionOS", _ => "", }, - (sym::target_arch, Some((arch, _))) => match arch.as_str() { + (sym::target_arch, Some(arch)) => match arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", "loongarch32" => "LoongArch LA32", @@ -605,14 +597,14 @@ impl fmt::Display for Display<'_> { "x86_64" => "x86-64", _ => "", }, - (sym::target_vendor, Some((vendor, _))) => match vendor.as_str() { + (sym::target_vendor, Some(vendor)) => match vendor.as_str() { "apple" => "Apple", "pc" => "PC", "sun" => "Sun", "fortanix" => "Fortanix", _ => "", }, - (sym::target_env, Some((env, _))) => match env.as_str() { + (sym::target_env, Some(env)) => match env.as_str() { "gnu" => "GNU", "msvc" => "MSVC", "musl" => "musl", @@ -621,20 +613,20 @@ impl fmt::Display for Display<'_> { "sgx" => "SGX", _ => "", }, - (sym::target_endian, Some((endian, _))) => { + (sym::target_endian, Some(endian)) => { return write!(fmt, "{endian}-endian"); } - (sym::target_pointer_width, Some((bits, _))) => { + (sym::target_pointer_width, Some(bits)) => { return write!(fmt, "{bits}-bit"); } - (sym::target_feature, Some((feat, _))) => match self.1 { + (sym::target_feature, Some(feat)) => match self.1 { Format::LongHtml => { return write!(fmt, "target feature {feat}"); } Format::LongPlain => return write!(fmt, "target feature `{feat}`"), Format::ShortHtml => return write!(fmt, "{feat}"), }, - (sym::feature, Some((feat, _))) => match self.1 { + (sym::feature, Some(feat)) => match self.1 { Format::LongHtml => { return write!(fmt, "crate feature {feat}"); } @@ -647,9 +639,7 @@ impl fmt::Display for Display<'_> { fmt.write_str(human_readable) } else { let value = value - .map(|(v, _)| { - fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))) - }) + .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str())))) .maybe_display(); self.code_wrappers() .wrap(format_args!("{}{value}", self.1.escape(name.as_str()))) @@ -684,9 +674,7 @@ impl NameValueCfg { impl<'a> From<&'a CfgEntry> for NameValueCfg { fn from(cfg: &'a CfgEntry) -> Self { match cfg { - CfgEntry::NameValue { name, value, .. } => { - NameValueCfg { name: *name, value: (*value).map(|(v, _)| v) } - } + CfgEntry::NameValue { name, value, .. } => NameValueCfg { name: *name, value: *value }, _ => NameValueCfg { name: sym::empty, value: None }, } } @@ -886,8 +874,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator for (feature, _) in features { cfg_info.current_cfg &= Cfg(CfgEntry::NameValue { name: sym::target_feature, - value: Some((*feature, DUMMY_SP)), - name_span: DUMMY_SP, + value: Some(*feature), span: DUMMY_SP, }); } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 4eb6c060cbd2..09316ead76ac 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -12,12 +12,7 @@ fn word_cfg(name: &str) -> Cfg { } fn word_cfg_e(name: &str) -> CfgEntry { - CfgEntry::NameValue { - name: Symbol::intern(name), - name_span: DUMMY_SP, - value: None, - span: DUMMY_SP, - } + CfgEntry::NameValue { name: Symbol::intern(name), value: None, span: DUMMY_SP } } fn name_value_cfg(name: &str, value: &str) -> Cfg { @@ -27,8 +22,8 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { CfgEntry::NameValue { name: Symbol::intern(name), - name_span: DUMMY_SP, - value: Some((Symbol::intern(value), DUMMY_SP)), + + value: Some(Symbol::intern(value)), span: DUMMY_SP, } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5e582eb61997..cc8a308688d2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,7 +32,6 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs deleted file mode 100644 index 9e7fae5e14e4..000000000000 --- a/src/librustdoc/passes/check_doc_cfg.rs +++ /dev/null @@ -1,72 +0,0 @@ -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Attribute, HirId}; -use rustc_middle::ty::TyCtxt; - -use super::Pass; -use crate::clean::{Attributes, Crate, Item}; -use crate::core::DocContext; -use crate::visit::DocVisitor; - -pub(crate) const CHECK_DOC_CFG: Pass = Pass { - name: "check-doc-cfg", - run: Some(check_doc_cfg), - description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", -}; - -pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut checker = DocCfgChecker { cx }; - checker.visit_crate(&krate); - krate -} - -struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); - -impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { - fn emit_span_lint( - &self, - sess: &rustc_session::Session, - lint: &'static rustc_lint::Lint, - sp: rustc_span::Span, - builtin_diag: rustc_lint_defs::BuiltinLintDiag, - ) { - self.0.node_span_lint(lint, self.1, sp, |diag| { - rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) - }); - } -} - -struct DocCfgChecker<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} - -impl DocCfgChecker<'_, '_> { - fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { - for attr in &attrs.other_attrs { - let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; - - for doc_cfg in &d.cfg { - let _ = eval_config_entry( - &self.cx.tcx.sess, - doc_cfg, - &RustdocCfgMatchesLintEmitter( - self.cx.tcx, - self.cx.tcx.local_def_id_to_hir_id(did), - ), - ShouldEmit::ErrorsAndLints, - ); - } - } - } -} - -impl DocVisitor<'_> for DocCfgChecker<'_, '_> { - fn visit_item(&mut self, item: &'_ Item) { - if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { - self.check_attrs(&item.attrs, local_did); - } - - self.visit_item_recur(item); - } -} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index a1e8e7530623..18e1afaf8a24 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -32,9 +32,6 @@ pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; mod check_doc_test_visibility; pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; -mod check_doc_cfg; -pub(crate) use self::check_doc_cfg::CHECK_DOC_CFG; - mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; @@ -75,7 +72,6 @@ pub(crate) enum Condition { /// The full list of passes. pub(crate) const PASSES: &[Pass] = &[ - CHECK_DOC_CFG, CHECK_DOC_TEST_VISIBILITY, PROPAGATE_DOC_CFG, STRIP_ALIASED_NON_LOCAL, @@ -93,7 +89,6 @@ pub(crate) const PASSES: &[Pass] = &[ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), - ConditionalPass::always(CHECK_DOC_CFG), ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::always(PROPAGATE_DOC_CFG), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), diff --git a/tests/rustdoc-ui/doc-cfg-2.rs b/tests/rustdoc-ui/doc-cfg-2.rs index bd6a2dc18be9..7a5d1f3e3dbb 100644 --- a/tests/rustdoc-ui/doc-cfg-2.rs +++ b/tests/rustdoc-ui/doc-cfg-2.rs @@ -12,5 +12,7 @@ // Shouldn't lint #[doc(auto_cfg(hide(windows)))] #[doc(auto_cfg(hide(feature = "windows")))] +//~^ WARN unexpected `cfg` condition name: `feature` #[doc(auto_cfg(hide(foo)))] +//~^ WARN unexpected `cfg` condition name: `foo` pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr index f3d67abfb8dd..1272e569897b 100644 --- a/tests/rustdoc-ui/doc-cfg-2.stderr +++ b/tests/rustdoc-ui/doc-cfg-2.stderr @@ -56,5 +56,23 @@ error: expected boolean for `#[doc(auto_cfg = ...)]` LL | #[doc(auto_cfg = "a")] | ^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +warning: unexpected `cfg` condition name: `feature` + --> $DIR/doc-cfg-2.rs:14:21 + | +LL | #[doc(auto_cfg(hide(feature = "windows")))] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(feature, values("windows"))` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-2.rs:16:21 + | +LL | #[doc(auto_cfg(hide(foo)))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + +error: aborting due to 6 previous errors; 4 warnings emitted diff --git a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr index 0878f7edbf48..3f67b85900aa 100644 --- a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr +++ b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr @@ -1,8 +1,8 @@ warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:12:12 + --> $DIR/doc-cfg-check-cfg.rs:15:11 | -LL | #![doc(cfg(foo))] - | ^^^ +LL | #[doc(cfg(foo))] + | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration @@ -18,10 +18,10 @@ LL | #[doc(cfg(foo))] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:15:11 + --> $DIR/doc-cfg-check-cfg.rs:12:12 | -LL | #[doc(cfg(foo))] - | ^^^ +LL | #![doc(cfg(foo))] + | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index c0cd454e8f3a..e7b8a1dccf80 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -1,5 +1,4 @@ Available passes for running rustdoc: - check-doc-cfg - checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs check_doc_test_visibility - run various visibility-related lints on doctests propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items strip-aliased-non-local - strips all non-local private aliased items from the output @@ -15,7 +14,6 @@ calculate-doc-coverage - counts the number of items with and without documentati Default passes for rustdoc: collect-trait-impls check_doc_test_visibility - check-doc-cfg strip-aliased-non-local propagate-doc-cfg strip-hidden (when not --document-hidden-items)