From 2ee6196078f76ff78279414fc336dfee0093331e Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 21 Nov 2025 14:42:02 -0600 Subject: [PATCH] validate usage of crate-level doc attributes --- compiler/rustc_passes/messages.ftl | 8 +++ compiler/rustc_passes/src/check_attr.rs | 31 +++++++++++- compiler/rustc_passes/src/errors.rs | 12 +++++ tests/rustdoc-ui/bad-render-options.rs | 11 ++++ tests/rustdoc-ui/bad-render-options.stderr | 58 ++++++++++++++++++++++ 5 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc-ui/bad-render-options.rs create mode 100644 tests/rustdoc-ui/bad-render-options.stderr diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index b33ccbae0e690..44177d4ae468c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -126,6 +126,14 @@ passes_doc_alias_not_string_literal = passes_doc_alias_start_end = {$attr_str} cannot start or end with ' ' +passes_doc_attr_expects_no_value = + `doc({$attr_name})` does not accept a value + .suggestion = use `doc({$attr_name})` + +passes_doc_attr_expects_string = + `doc({$attr_name})` expects a string value + .suggestion = use `doc({$attr_name} = "...")` + passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 347e103af9378..94bdb1e571bc2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1122,6 +1122,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } + fn check_doc_attr_string_value(&self, meta: &MetaItemInner, hir_id: HirId) { + if meta.value_str().is_none() { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocAttrExpectsString { attr_name: meta.name().unwrap() }, + ); + } + } + + fn check_doc_attr_no_value(&self, meta: &MetaItemInner, hir_id: HirId) { + if !meta.is_word() { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocAttrExpectsNoValue { attr_name: meta.name().unwrap() }, + ); + } + } + /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. fn check_test_attr( &self, @@ -1292,10 +1314,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::html_logo_url | sym::html_playground_url | sym::issue_tracker_base_url - | sym::html_root_url - | sym::html_no_source, + | sym::html_root_url, ) => { self.check_attr_crate_level(attr_span, style, meta, hir_id); + self.check_doc_attr_string_value(meta, hir_id); + } + + Some(sym::html_no_source) => { + self.check_attr_crate_level(attr_span, style, meta, hir_id); + self.check_doc_attr_no_value(meta, hir_id); } Some(sym::auto_cfg) => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ed4cf77d294fd..e4826cccd32f8 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -24,6 +24,18 @@ pub(crate) struct IncorrectDoNotRecommendLocation; #[diag(passes_incorrect_do_not_recommend_args)] pub(crate) struct DoNotRecommendDoesNotExpectArgs; +#[derive(LintDiagnostic)] +#[diag(passes_doc_attr_expects_string)] +pub(crate) struct DocAttrExpectsString { + pub(crate) attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(passes_doc_attr_expects_no_value)] +pub(crate) struct DocAttrExpectsNoValue { + pub(crate) attr_name: Symbol, +} + #[derive(Diagnostic)] #[diag(passes_autodiff_attr)] pub(crate) struct AutoDiffAttr { diff --git a/tests/rustdoc-ui/bad-render-options.rs b/tests/rustdoc-ui/bad-render-options.rs new file mode 100644 index 0000000000000..f2cfd4b76fa8c --- /dev/null +++ b/tests/rustdoc-ui/bad-render-options.rs @@ -0,0 +1,11 @@ +// regression test for https://github.com/rust-lang/rust/issues/149187 + +#![doc(html_favicon_url)] //~ ERROR: `doc(html_favicon_url)` expects a string value [invalid_doc_attributes] +#![doc(html_logo_url)] //~ ERROR: `doc(html_logo_url)` expects a string value [invalid_doc_attributes] +#![doc(html_playground_url)] //~ ERROR: `doc(html_playground_url)` expects a string value [invalid_doc_attributes] +#![doc(issue_tracker_base_url)] //~ ERROR expects a string value +#![doc(html_favicon_url = 1)] //~ ERROR expects a string value +#![doc(html_logo_url = 2)] //~ ERROR expects a string value +#![doc(html_playground_url = 3)] //~ ERROR expects a string value +#![doc(issue_tracker_base_url = 4)] //~ ERROR expects a string value +#![doc(html_no_source = "asdf")] //~ ERROR `doc(html_no_source)` does not accept a value [invalid_doc_attributes] diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr new file mode 100644 index 0000000000000..9d503363c0bd9 --- /dev/null +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -0,0 +1,58 @@ +error: `doc(html_favicon_url)` expects a string value + --> $DIR/bad-render-options.rs:3:8 + | +LL | #![doc(html_favicon_url)] + | ^^^^^^^^^^^^^^^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: `doc(html_logo_url)` expects a string value + --> $DIR/bad-render-options.rs:4:8 + | +LL | #![doc(html_logo_url)] + | ^^^^^^^^^^^^^ + +error: `doc(html_playground_url)` expects a string value + --> $DIR/bad-render-options.rs:5:8 + | +LL | #![doc(html_playground_url)] + | ^^^^^^^^^^^^^^^^^^^ + +error: `doc(issue_tracker_base_url)` expects a string value + --> $DIR/bad-render-options.rs:6:8 + | +LL | #![doc(issue_tracker_base_url)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: `doc(html_favicon_url)` expects a string value + --> $DIR/bad-render-options.rs:7:8 + | +LL | #![doc(html_favicon_url = 1)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `doc(html_logo_url)` expects a string value + --> $DIR/bad-render-options.rs:8:8 + | +LL | #![doc(html_logo_url = 2)] + | ^^^^^^^^^^^^^^^^^ + +error: `doc(html_playground_url)` expects a string value + --> $DIR/bad-render-options.rs:9:8 + | +LL | #![doc(html_playground_url = 3)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: `doc(issue_tracker_base_url)` expects a string value + --> $DIR/bad-render-options.rs:10:8 + | +LL | #![doc(issue_tracker_base_url = 4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `doc(html_no_source)` does not accept a value + --> $DIR/bad-render-options.rs:11:8 + | +LL | #![doc(html_no_source = "asdf")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors +