Tweak attribute rendering depending on wether or not it is a type alias
This commit is contained in:
@@ -815,67 +815,7 @@ impl Item {
|
||||
|
||||
/// Returns a `#[repr(...)]` representation.
|
||||
pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
|
||||
use rustc_abi::IntegerType;
|
||||
|
||||
let def_id = self.def_id()?;
|
||||
if !matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) {
|
||||
return None;
|
||||
}
|
||||
let adt = tcx.adt_def(def_id);
|
||||
let repr = adt.repr();
|
||||
let mut out = Vec::new();
|
||||
if repr.c() {
|
||||
out.push("C");
|
||||
}
|
||||
if repr.transparent() {
|
||||
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
|
||||
// field is public in case all fields are 1-ZST fields.
|
||||
let render_transparent = is_json
|
||||
|| cache.document_private
|
||||
|| adt
|
||||
.all_fields()
|
||||
.find(|field| {
|
||||
let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
|
||||
tcx.layout_of(
|
||||
ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
|
||||
)
|
||||
.is_ok_and(|layout| !layout.is_1zst())
|
||||
})
|
||||
.map_or_else(
|
||||
|| adt.all_fields().any(|field| field.vis.is_public()),
|
||||
|field| field.vis.is_public(),
|
||||
);
|
||||
|
||||
if render_transparent {
|
||||
out.push("transparent");
|
||||
}
|
||||
}
|
||||
if repr.simd() {
|
||||
out.push("simd");
|
||||
}
|
||||
let pack_s;
|
||||
if let Some(pack) = repr.pack {
|
||||
pack_s = format!("packed({})", pack.bytes());
|
||||
out.push(&pack_s);
|
||||
}
|
||||
let align_s;
|
||||
if let Some(align) = repr.align {
|
||||
align_s = format!("align({})", align.bytes());
|
||||
out.push(&align_s);
|
||||
}
|
||||
let int_s;
|
||||
if let Some(int) = repr.int {
|
||||
int_s = match int {
|
||||
IntegerType::Pointer(is_signed) => {
|
||||
format!("{}size", if is_signed { 'i' } else { 'u' })
|
||||
}
|
||||
IntegerType::Fixed(size, is_signed) => {
|
||||
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
|
||||
}
|
||||
};
|
||||
out.push(&int_s);
|
||||
}
|
||||
if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
|
||||
repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
|
||||
}
|
||||
|
||||
pub fn is_doc_hidden(&self) -> bool {
|
||||
@@ -887,6 +827,73 @@ impl Item {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn repr_attributes(
|
||||
tcx: TyCtxt<'_>,
|
||||
cache: &Cache,
|
||||
def_id: DefId,
|
||||
item_type: ItemType,
|
||||
is_json: bool,
|
||||
) -> Option<String> {
|
||||
use rustc_abi::IntegerType;
|
||||
|
||||
if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
|
||||
return None;
|
||||
}
|
||||
let adt = tcx.adt_def(def_id);
|
||||
let repr = adt.repr();
|
||||
let mut out = Vec::new();
|
||||
if repr.c() {
|
||||
out.push("C");
|
||||
}
|
||||
if repr.transparent() {
|
||||
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
|
||||
// field is public in case all fields are 1-ZST fields.
|
||||
let render_transparent = cache.document_private
|
||||
|| is_json
|
||||
|| adt
|
||||
.all_fields()
|
||||
.find(|field| {
|
||||
let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
|
||||
tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
|
||||
.is_ok_and(|layout| !layout.is_1zst())
|
||||
})
|
||||
.map_or_else(
|
||||
|| adt.all_fields().any(|field| field.vis.is_public()),
|
||||
|field| field.vis.is_public(),
|
||||
);
|
||||
|
||||
if render_transparent {
|
||||
out.push("transparent");
|
||||
}
|
||||
}
|
||||
if repr.simd() {
|
||||
out.push("simd");
|
||||
}
|
||||
let pack_s;
|
||||
if let Some(pack) = repr.pack {
|
||||
pack_s = format!("packed({})", pack.bytes());
|
||||
out.push(&pack_s);
|
||||
}
|
||||
let align_s;
|
||||
if let Some(align) = repr.align {
|
||||
align_s = format!("align({})", align.bytes());
|
||||
out.push(&align_s);
|
||||
}
|
||||
let int_s;
|
||||
if let Some(int) = repr.int {
|
||||
int_s = match int {
|
||||
IntegerType::Pointer(is_signed) => {
|
||||
format!("{}size", if is_signed { 'i' } else { 'u' })
|
||||
}
|
||||
IntegerType::Fixed(size, is_signed) => {
|
||||
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
|
||||
}
|
||||
};
|
||||
out.push(&int_s);
|
||||
}
|
||||
if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum ItemKind {
|
||||
ExternCrateItem {
|
||||
|
||||
@@ -1201,11 +1201,31 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) ->
|
||||
})
|
||||
}
|
||||
|
||||
struct CodeAttribute(String);
|
||||
|
||||
impl CodeAttribute {
|
||||
fn render_into(self, w: &mut impl fmt::Write) {
|
||||
write!(w, "<div class=\"code-attribute\">{}</div>", self.0).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// When an attribute is rendered inside a <code> tag, it is formatted using
|
||||
// a div to produce a newline after it.
|
||||
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
|
||||
for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
|
||||
write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
|
||||
CodeAttribute(attr).render_into(w);
|
||||
}
|
||||
}
|
||||
|
||||
/// used for type aliases to only render their `repr` attribute.
|
||||
fn render_repr_attributes_in_code(
|
||||
w: &mut impl fmt::Write,
|
||||
cx: &Context<'_>,
|
||||
def_id: DefId,
|
||||
item_type: ItemType,
|
||||
) {
|
||||
if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
|
||||
CodeAttribute(repr).render_into(w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ use super::{
|
||||
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
|
||||
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
|
||||
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
|
||||
render_impl, render_rightside, render_stability_since_raw,
|
||||
render_impl, render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
|
||||
render_stability_since_raw_with_extra, write_section_heading,
|
||||
};
|
||||
use crate::clean;
|
||||
@@ -1290,12 +1290,30 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) ->
|
||||
.render_into(cx, it, true, w)?;
|
||||
}
|
||||
clean::TypeAliasInnerType::Union { fields } => {
|
||||
ItemUnion { cx, it, fields, generics: &t.generics, is_type_alias: true }
|
||||
.render_into(w)?;
|
||||
let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
|
||||
let union_def_id = ty.ty_adt_def().unwrap().did();
|
||||
|
||||
ItemUnion {
|
||||
cx,
|
||||
it,
|
||||
fields,
|
||||
generics: &t.generics,
|
||||
is_type_alias: true,
|
||||
def_id: union_def_id,
|
||||
}
|
||||
.render_into(w)?;
|
||||
}
|
||||
clean::TypeAliasInnerType::Struct { ctor_kind, fields } => {
|
||||
DisplayStruct { ctor_kind: *ctor_kind, generics: &t.generics, fields }
|
||||
.render_into(cx, it, true, w)?;
|
||||
let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
|
||||
let struct_def_id = ty.ty_adt_def().unwrap().did();
|
||||
|
||||
DisplayStruct {
|
||||
ctor_kind: *ctor_kind,
|
||||
generics: &t.generics,
|
||||
fields,
|
||||
def_id: struct_def_id,
|
||||
}
|
||||
.render_into(cx, it, true, w)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1417,8 +1435,9 @@ item_template!(
|
||||
fields: &'a [clean::Item],
|
||||
generics: &'a clean::Generics,
|
||||
is_type_alias: bool,
|
||||
def_id: DefId,
|
||||
},
|
||||
methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items]
|
||||
methods = [document, document_type_layout, render_assoc_items]
|
||||
);
|
||||
|
||||
impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
||||
@@ -1449,13 +1468,41 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
||||
})
|
||||
.peekable()
|
||||
}
|
||||
|
||||
fn render_attributes_in_pre(&self) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| {
|
||||
if !self.is_type_alias {
|
||||
for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) {
|
||||
writeln!(f, "{a}")?;
|
||||
}
|
||||
} else {
|
||||
// For now we only render `repr` attributes for type aliases.
|
||||
if let Some(repr) = clean::repr_attributes(
|
||||
self.cx.tcx(),
|
||||
self.cx.cache(),
|
||||
self.def_id,
|
||||
ItemType::Union,
|
||||
) {
|
||||
writeln!(f, "{repr}")?;
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display {
|
||||
fmt::from_fn(|w| {
|
||||
ItemUnion { cx, it, fields: &s.fields, generics: &s.generics, is_type_alias: false }
|
||||
.render_into(w)
|
||||
.unwrap();
|
||||
ItemUnion {
|
||||
cx,
|
||||
it,
|
||||
fields: &s.fields,
|
||||
generics: &s.generics,
|
||||
is_type_alias: false,
|
||||
def_id: it.def_id().unwrap(),
|
||||
}
|
||||
.render_into(w)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -1502,7 +1549,12 @@ impl<'a> DisplayEnum<'a> {
|
||||
let has_stripped_entries = variants_len != variants_count;
|
||||
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
if !is_type_alias {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
} else {
|
||||
// For now we only render `repr` attributes for type aliases.
|
||||
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
"{}enum {}{}{}",
|
||||
@@ -1521,19 +1573,22 @@ impl<'a> DisplayEnum<'a> {
|
||||
)
|
||||
})?;
|
||||
|
||||
if !is_type_alias {
|
||||
let def_id = it.item_id.expect_def_id();
|
||||
let layout_def_id = if !is_type_alias {
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
|
||||
}
|
||||
def_id
|
||||
} else {
|
||||
self.def_id
|
||||
};
|
||||
|
||||
if variants_count != 0 {
|
||||
write!(w, "{}", item_variants(cx, it, self.variants, self.def_id))?;
|
||||
}
|
||||
let def_id = it.item_id.expect_def_id();
|
||||
write!(
|
||||
w,
|
||||
"{}{}",
|
||||
render_assoc_items(cx, it, def_id, AssocItemRender::All),
|
||||
document_type_layout(cx, def_id)
|
||||
document_type_layout(cx, layout_def_id)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1938,6 +1993,7 @@ struct DisplayStruct<'a> {
|
||||
ctor_kind: Option<CtorKind>,
|
||||
generics: &'a clean::Generics,
|
||||
fields: &'a [clean::Item],
|
||||
def_id: DefId,
|
||||
}
|
||||
|
||||
impl<'a> DisplayStruct<'a> {
|
||||
@@ -1949,7 +2005,12 @@ impl<'a> DisplayStruct<'a> {
|
||||
w: &mut W,
|
||||
) -> fmt::Result {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
if !is_type_alias {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
} else {
|
||||
// For now we only render `repr` attributes for type aliases.
|
||||
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
"{}",
|
||||
@@ -1974,8 +2035,13 @@ impl<'a> DisplayStruct<'a> {
|
||||
|
||||
fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display {
|
||||
fmt::from_fn(|w| {
|
||||
DisplayStruct { ctor_kind: s.ctor_kind, generics: &s.generics, fields: s.fields.as_slice() }
|
||||
.render_into(cx, it, false, w)
|
||||
DisplayStruct {
|
||||
ctor_kind: s.ctor_kind,
|
||||
generics: &s.generics,
|
||||
fields: s.fields.as_slice(),
|
||||
def_id: it.def_id().unwrap(),
|
||||
}
|
||||
.render_into(cx, it, false, w)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ pub type TypeAlias = X;
|
||||
pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>);
|
||||
|
||||
// Regression test for the rustdoc equivalent of #85103.
|
||||
//@ hasraw type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.'
|
||||
//@ hasraw type_layout/type.Edges.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.'
|
||||
pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>;
|
||||
|
||||
//@ !hasraw type_layout/trait.MyTrait.html 'Size: '
|
||||
|
||||
Reference in New Issue
Block a user