Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
17 changes: 9 additions & 8 deletions compiler/rustc_attr_parsing/src/target_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<_>>();
if !spans.is_empty() {
self.dcx()
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Symbol, Span>,
pub hidden: Option<Span>,
// Because we need to emit the error if there is more than one `inline` attribute on an item
Expand Down Expand Up @@ -581,6 +583,7 @@ pub struct DocAttribute {
impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute {
fn encode(&self, encoder: &mut E) {
let DocAttribute {
first_span,
aliases,
hidden,
inline,
Expand All @@ -603,6 +606,7 @@ impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute
test_attrs,
no_crate_inject,
} = self;
rustc_serialize::Encodable::<E>::encode(first_span, encoder);
rustc_serialize::Encodable::<E>::encode(aliases, encoder);
rustc_serialize::Encodable::<E>::encode(hidden, encoder);

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>)
}

let DocAttribute {
first_span: _,
aliases,
hidden,
inline,
Expand Down
34 changes: 34 additions & 0 deletions tests/ui/attributes/where-doc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![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
():,

// == That the doc attributes below don't trigger the error is a bug

@JonathanBrouwer JonathanBrouwer Apr 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bug is not caused by this PR, but I did decide to document the bug in a test and I will make a follow-up PR to address it

View changes since the review

#[doc()]
():,

#[doc(5)]
():,

#[doc]
():,

#[doc = 5]
():,

{ }

fn main() {}
32 changes: 32 additions & 0 deletions tests/ui/attributes/where-doc.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading