Update to new API, allowing to remove check_doc_cfg.rs file from librustdoc

This commit is contained in:
Guillaume Gomez 2025-12-09 22:27:28 +01:00
parent 40907f522d
commit 64aaeacd71
13 changed files with 59 additions and 135 deletions

View file

@ -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;

View file

@ -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)),
})
}
}
_ => {

View file

@ -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}"),
}
}

View file

@ -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"

View file

@ -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 <code>{feat}</code>");
}
Format::LongPlain => return write!(fmt, "target feature `{feat}`"),
Format::ShortHtml => return write!(fmt, "<code>{feat}</code>"),
},
(sym::feature, Some((feat, _))) => match self.1 {
(sym::feature, Some(feat)) => match self.1 {
Format::LongHtml => {
return write!(fmt, "crate feature <code>{feat}</code>");
}
@ -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<Item = &'a hir::Attribute>
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,
});
}

View file

@ -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,
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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),

View file

@ -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() {}

View file

@ -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 <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
error: aborting due to 6 previous errors; 4 warnings emitted

View file

@ -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 <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
@ -18,10 +18,10 @@ LL | #[doc(cfg(foo))]
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration

View file

@ -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)