diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2025-08-28 21:41:00 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-28 21:41:00 +0200 |
| commit | f948c79911844709ad8aeea23b211fb9790257c7 (patch) | |
| tree | 21eee94893fd60d7cfa906db0156556405f67dfb /compiler/rustc_passes/src | |
| parent | 1f7dcc878d73c45cc40018aac6e5c767446df110 (diff) | |
| parent | f3c023433f6e44be208f9e3bb74528449da730c1 (diff) | |
| download | rust-f948c79911844709ad8aeea23b211fb9790257c7.tar.gz rust-f948c79911844709ad8aeea23b211fb9790257c7.zip | |
Rollup merge of #142472 - GuillaumeGomez:doc-attribute-attribute, r=fmease
Add new `doc(attribute = "...")` attribute Fixes rust-lang/rust#141123. The implementation and purpose of this new `#[doc(attribute = "...")]` attribute is very close to `#[doc(keyword = "...")]`. Which means that luckily for us, most of the code needed was already in place and `@Noratrieb` nicely wrote a first draft that helped me implement this new attribute very fast. Now with all this said, there is one thing I didn't do yet: adding a `rustdoc-js-std` test. I added GUI tests with search results for attributes so should be fine but I still plan on adding one for it once documentation for builtin attributes will be written into the core/std libs. You can test it [here](https://rustdoc.crud.net/imperio/doc-attribute-attribute/foo/index.html). cc `@Noratrieb` `@Veykril`
Diffstat (limited to 'compiler/rustc_passes/src')
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 79 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/errors.rs | 19 |
2 files changed, 83 insertions, 15 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c47b488465b..2cd4830b5d9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -99,6 +99,21 @@ impl IntoDiagArg for ProcMacroKind { } } +#[derive(Clone, Copy)] +enum DocFakeItemKind { + Attribute, + Keyword, +} + +impl DocFakeItemKind { + fn name(self) -> &'static str { + match self { + Self::Attribute => "attribute", + Self::Keyword => "keyword", + } + } +} + struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -853,7 +868,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) { + fn check_doc_keyword_and_attribute( + &self, + meta: &MetaItemInner, + hir_id: HirId, + attr_kind: DocFakeItemKind, + ) { fn is_doc_keyword(s: Symbol) -> bool { // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the @@ -861,9 +881,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy } - let doc_keyword = match meta.value_str() { + // FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`. + fn is_builtin_attr(s: Symbol) -> bool { + rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s) + } + + let value = match meta.value_str() { Some(value) if value != sym::empty => value, - _ => return self.doc_attr_str_error(meta, "keyword"), + _ => return self.doc_attr_str_error(meta, attr_kind.name()), }; let item_kind = match self.tcx.hir_node(hir_id) { @@ -873,20 +898,38 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match item_kind { Some(ItemKind::Mod(_, module)) => { if !module.item_ids.is_empty() { - self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() }); + self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod { + span: meta.span(), + attr_name: attr_kind.name(), + }); return; } } _ => { - self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() }); + self.dcx().emit_err(errors::DocKeywordAttributeNotMod { + span: meta.span(), + attr_name: attr_kind.name(), + }); return; } } - if !is_doc_keyword(doc_keyword) { - self.dcx().emit_err(errors::DocKeywordNotKeyword { - span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - keyword: doc_keyword, - }); + match attr_kind { + DocFakeItemKind::Keyword => { + if !is_doc_keyword(value) { + self.dcx().emit_err(errors::DocKeywordNotKeyword { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + keyword: value, + }); + } + } + DocFakeItemKind::Attribute => { + if !is_builtin_attr(value) { + self.dcx().emit_err(errors::DocAttributeNotAttribute { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + attribute: value, + }); + } + } } } @@ -1146,7 +1189,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Some(sym::keyword) => { if self.check_attr_not_crate_level(meta, hir_id, "keyword") { - self.check_doc_keyword(meta, hir_id); + self.check_doc_keyword_and_attribute( + meta, + hir_id, + DocFakeItemKind::Keyword, + ); + } + } + + Some(sym::attribute) => { + if self.check_attr_not_crate_level(meta, hir_id, "attribute") { + self.check_doc_keyword_and_attribute( + meta, + hir_id, + DocFakeItemKind::Attribute, + ); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 01972067978..680e2a26d84 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -195,10 +195,11 @@ pub(crate) struct DocAliasMalformed { } #[derive(Diagnostic)] -#[diag(passes_doc_keyword_empty_mod)] -pub(crate) struct DocKeywordEmptyMod { +#[diag(passes_doc_keyword_attribute_empty_mod)] +pub(crate) struct DocKeywordAttributeEmptyMod { #[primary_span] pub span: Span, + pub attr_name: &'static str, } #[derive(Diagnostic)] @@ -211,10 +212,20 @@ pub(crate) struct DocKeywordNotKeyword { } #[derive(Diagnostic)] -#[diag(passes_doc_keyword_not_mod)] -pub(crate) struct DocKeywordNotMod { +#[diag(passes_doc_attribute_not_attribute)] +#[help] +pub(crate) struct DocAttributeNotAttribute { + #[primary_span] + pub span: Span, + pub attribute: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_doc_keyword_attribute_not_mod)] +pub(crate) struct DocKeywordAttributeNotMod { #[primary_span] pub span: Span, + pub attr_name: &'static str, } #[derive(Diagnostic)] |
