Port #[rustc_doc_primitive] to the new attribute parser

This commit is contained in:
Oscar Bray
2026-02-16 22:02:50 +00:00
parent c043085801
commit bd54cd66a1
10 changed files with 59 additions and 21 deletions
+7
View File
@@ -296,6 +296,10 @@ fn is_doc_keyword_or_attribute(&self) -> bool {
}
false
}
fn is_rustc_doc_primitive(&self) -> bool {
self.has_name(sym::rustc_doc_primitive)
}
}
impl Attribute {
@@ -935,6 +939,9 @@ fn is_proc_macro_attr(&self) -> bool {
/// Returns `true` is this attribute contains `doc(keyword)` or `doc(attribute)`.
fn is_doc_keyword_or_attribute(&self) -> bool;
/// Returns `true` if this is a `#[rustc_doc_primitive]` attribute.
fn is_rustc_doc_primitive(&self) -> bool;
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding
@@ -1319,3 +1319,27 @@ impl<S: Stage> NoArgsAttributeParser<S> for PreludeImportParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;
}
pub(crate) struct RustcDocPrimitiveParser;
impl<S: Stage> SingleAttributeParser<S> for RustcDocPrimitiveParser {
const PATH: &[Symbol] = &[sym::rustc_doc_primitive];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(cx.attr_span), None);
return None;
};
let Some(value_str) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
Some(AttributeKind::RustcDocPrimitive(cx.attr_span, value_str))
}
}
@@ -205,6 +205,7 @@ mod late {
Single<RustcDefPath>,
Single<RustcDeprecatedSafe2024Parser>,
Single<RustcDiagnosticItemParser>,
Single<RustcDocPrimitiveParser>,
Single<RustcForceInlineParser>,
Single<RustcIfThisChangedParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
@@ -1169,6 +1169,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_do_not_const_check]`
RustcDoNotConstCheck,
/// Represents `#[rustc_doc_primitive = ...]`
RustcDocPrimitive(Span, Symbol),
/// Represents `#[rustc_dummy]`.
RustcDummy,
@@ -117,6 +117,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
RustcDeprecatedSafe2024 { .. } => Yes,
RustcDiagnosticItem(..) => Yes,
RustcDoNotConstCheck => Yes,
RustcDocPrimitive(..) => Yes,
RustcDummy => No,
RustcDumpDefParents => No,
RustcDumpItemBounds => No,
+4
View File
@@ -1467,6 +1467,10 @@ fn is_doc_hidden(&self) -> bool {
fn is_doc_keyword_or_attribute(&self) -> bool {
matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.attribute.is_some() || d.keyword.is_some())
}
fn is_rustc_doc_primitive(&self) -> bool {
matches!(self, Attribute::Parsed(AttributeKind::RustcDocPrimitive(..)))
}
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding
+1 -1
View File
@@ -312,6 +312,7 @@ fn check_attributes(
| AttributeKind::RustcDeprecatedSafe2024 {..}
| AttributeKind::RustcDiagnosticItem(..)
| AttributeKind::RustcDoNotConstCheck
| AttributeKind::RustcDocPrimitive(..)
| AttributeKind::RustcDummy
| AttributeKind::RustcDumpDefParents
| AttributeKind::RustcDumpItemBounds
@@ -402,7 +403,6 @@ fn check_attributes(
// internal
| sym::rustc_inherit_overflow_checks
| sym::rustc_on_unimplemented
| sym::rustc_doc_primitive
| sym::rustc_layout
| sym::rustc_autodiff
| sym::rustc_capture_analysis
+1 -1
View File
@@ -367,7 +367,7 @@ pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool {
/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`.
pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -> bool {
for attr in attrs {
if attr.has_name(sym::rustc_doc_primitive) || attr.is_doc_keyword_or_attribute() {
if attr.is_rustc_doc_primitive() || attr.is_doc_keyword_or_attribute() {
return true;
}
}
+10 -11
View File
@@ -308,17 +308,16 @@ pub(crate) fn primitives(
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
tcx.get_attrs(def_id, sym::rustc_doc_primitive).next().map(|attr| {
let attr_value = attr.value_str().expect("syntax should already be validated");
let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
span_bug!(
attr.span(),
"primitive `{attr_value}` is not a member of `PrimitiveType`"
);
};
(def_id, prim)
})
let Some((attr_span, prim_sym)) = find_attr!(
tcx.get_all_attrs(def_id),
AttributeKind::RustcDocPrimitive(span, prim) => (*span, *prim)
) else {
return None;
};
let Some(prim) = PrimitiveType::from_symbol(prim_sym) else {
span_bug!(attr_span, "primitive `{prim_sym}` is not a member of `PrimitiveType`");
};
Some((def_id, prim))
}
self.mapped_root_modules(tcx, as_primitive)
+7 -8
View File
@@ -6,9 +6,10 @@
//! other phases think of as an "item".
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::DefId;
use rustc_span::{Symbol, sym};
use rustc_hir::find_attr;
use rustc_span::Symbol;
use rustdoc_json_types as types;
use super::JsonRenderer;
@@ -88,12 +89,10 @@ fn id_from_item_inner(
// We need this workaround because primitive types' DefId actually refers to
// their parent module, which isn't present in the output JSON items. So
// instead, we directly get the primitive symbol
if matches!(self.tcx.def_kind(def_id), DefKind::Mod)
&& let Some(prim) = self
.tcx
.get_attrs(def_id, sym::rustc_doc_primitive)
.find_map(|attr| attr.value_str())
{
if let Some(prim) = find_attr!(
self.tcx.get_all_attrs(def_id),
AttributeKind::RustcDocPrimitive(_, prim) => *prim
) {
Some(prim)
} else {
self.tcx.opt_item_name(def_id)