From cafe02e1e353c1ddb72b4981d3beb97d4f99eba3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 27 Apr 2026 09:47:23 +0200 Subject: [PATCH 1/3] Add `first_span` to doc attribute --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 3 +++ compiler/rustc_hir/src/attrs/data_structures.rs | 4 ++++ compiler/rustc_passes/src/check_attr.rs | 1 + src/librustdoc/clean/mod.rs | 1 + src/librustdoc/json/conversions.rs | 1 + 5 files changed, 10 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 5d07478b152ee..60f469990d51a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -701,6 +701,9 @@ impl DocParser { for i in items.mixed() { match i { MetaItemOrLitParser::MetaItemParser(mip) => { + if self.nb_doc_attrs == 0 { + self.attribute.first_span = cx.attr_span; + } self.nb_doc_attrs += 1; self.parse_single_doc_attr_item(cx, mip); } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 6304b830f6ed7..bab86a25e3cbb 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -544,6 +544,8 @@ pub struct CfgHideShow { #[derive(Clone, Debug, Default, HashStable_Generic, Decodable, PrintAttribute)] pub struct DocAttribute { + pub first_span: Span, + pub aliases: FxIndexMap, pub hidden: Option, // Because we need to emit the error if there is more than one `inline` attribute on an item @@ -581,6 +583,7 @@ pub struct DocAttribute { impl rustc_serialize::Encodable for DocAttribute { fn encode(&self, encoder: &mut E) { let DocAttribute { + first_span, aliases, hidden, inline, @@ -603,6 +606,7 @@ impl rustc_serialize::Encodable for DocAttribute test_attrs, no_crate_inject, } = self; + rustc_serialize::Encodable::::encode(first_span, encoder); rustc_serialize::Encodable::::encode(aliases, encoder); rustc_serialize::Encodable::::encode(hidden, encoder); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ebf0f06f7173d..34c2ec54e8fc9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1027,6 +1027,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// [`check_doc_inline`]: Self::check_doc_inline fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) { let DocAttribute { + first_span: _, aliases, // valid pretty much anywhere, not checked here? // FIXME: should we? diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 81e348f96e569..3f604c1b7bb8b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2780,6 +2780,7 @@ fn add_without_unwanted_attributes<'hir>( hir::Attribute::Parsed(AttributeKind::Doc(box d)) => { // Remove attributes from `normal` that should not be inherited by `use` re-export. let DocAttribute { + first_span: _, aliases, hidden, inline, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5d1f4778f1c52..44749fd4c0ec6 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -960,6 +960,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) } let DocAttribute { + first_span: _, aliases, hidden, inline, From 71ef1fafe02bd7b62bbdbecf050977d037c90eb3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 27 Apr 2026 09:48:51 +0200 Subject: [PATCH 2/3] Rewrite `check_invalid_where_predicate_attrs` --- .../rustc_attr_parsing/src/target_checking.rs | 17 +++++----- tests/ui/attributes/where-doc.rs | 21 ++++++++++++ tests/ui/attributes/where-doc.stderr | 32 +++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 tests/ui/attributes/where-doc.rs create mode 100644 tests/ui/attributes/where-doc.stderr diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 65e716921f5cb..8c41d7732c7d5 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -292,15 +292,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // in where clauses. After that, this function would become useless. let spans = attrs .into_iter() - // FIXME: We shouldn't need to special-case `doc`! - .filter(|attr| { - matches!( - attr, - Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_)) - | Attribute::Unparsed(_) - ) + .filter_map(|attr| { + match attr { + Attribute::Parsed(AttributeKind::DocComment { span, .. }) => Some(*span), + // FIXME: We shouldn't need to special-case `doc`! + Attribute::Parsed(AttributeKind::Doc(attr)) => Some(attr.first_span), + // Checked during attribute parsing target checking + Attribute::Parsed(_) => None, + Attribute::Unparsed(attr) => Some(attr.span), + } }) - .map(|attr| attr.span()) .collect::>(); if !spans.is_empty() { self.dcx() diff --git a/tests/ui/attributes/where-doc.rs b/tests/ui/attributes/where-doc.rs new file mode 100644 index 0000000000000..12fcc71484cb4 --- /dev/null +++ b/tests/ui/attributes/where-doc.rs @@ -0,0 +1,21 @@ +#![feature(where_clause_attrs)] +#![allow(invalid_doc_attributes)] + +fn test() +where +#[doc(alias = ":(")] +//~^ ERROR most attributes are not supported in `where` clauses +//~| ERROR `#[doc(alias = "...")]` isn't allowed on where predicate +():, + +#[doc(hidden)] +//~^ ERROR most attributes are not supported in `where` clauses +():, + +#[doc = ""] +//~^ ERROR most attributes are not supported in `where` clauses +():, + +{ } + +fn main() {} diff --git a/tests/ui/attributes/where-doc.stderr b/tests/ui/attributes/where-doc.stderr new file mode 100644 index 0000000000000..c8efaaeedfaac --- /dev/null +++ b/tests/ui/attributes/where-doc.stderr @@ -0,0 +1,32 @@ +error: most attributes are not supported in `where` clauses + --> $DIR/where-doc.rs:6:1 + | +LL | #[doc(alias = ":(")] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/where-doc.rs:11:1 + | +LL | #[doc(hidden)] + | ^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/where-doc.rs:15:1 + | +LL | #[doc = ""] + | ^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: `#[doc(alias = "...")]` isn't allowed on where predicate + --> $DIR/where-doc.rs:6:15 + | +LL | #[doc(alias = ":(")] + | ^^^^ + +error: aborting due to 4 previous errors + From 75fa098069941f0aa4223ead622528cb2ce4982c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 27 Apr 2026 09:52:43 +0200 Subject: [PATCH 3/3] Add test for existing bug --- tests/ui/attributes/where-doc.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/ui/attributes/where-doc.rs b/tests/ui/attributes/where-doc.rs index 12fcc71484cb4..761d83966f659 100644 --- a/tests/ui/attributes/where-doc.rs +++ b/tests/ui/attributes/where-doc.rs @@ -16,6 +16,19 @@ where //~^ ERROR most attributes are not supported in `where` clauses ():, +// == That the doc attributes below don't trigger the error is a bug +#[doc()] +():, + +#[doc(5)] +():, + +#[doc] +():, + +#[doc = 5] +():, + { } fn main() {}