Skip to content

Commit 376e51e

Browse files
Tweak attribute rendering depending on wether or not it is a type alias
1 parent ca874e7 commit 376e51e

File tree

4 files changed

+171
-79
lines changed

4 files changed

+171
-79
lines changed

src/librustdoc/clean/types.rs

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -822,66 +822,7 @@ impl Item {
822822

823823
/// Returns a `#[repr(...)]` representation.
824824
pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
825-
use rustc_abi::IntegerType;
826-
827-
let def_id = self.def_id()?;
828-
if !matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) {
829-
return None;
830-
}
831-
let adt = tcx.adt_def(def_id);
832-
let repr = adt.repr();
833-
let mut out = Vec::new();
834-
if repr.c() {
835-
out.push("C");
836-
}
837-
if repr.transparent() {
838-
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
839-
// field is public in case all fields are 1-ZST fields.
840-
let render_transparent = cache.document_private
841-
|| adt
842-
.all_fields()
843-
.find(|field| {
844-
let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
845-
tcx.layout_of(
846-
ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
847-
)
848-
.is_ok_and(|layout| !layout.is_1zst())
849-
})
850-
.map_or_else(
851-
|| adt.all_fields().any(|field| field.vis.is_public()),
852-
|field| field.vis.is_public(),
853-
);
854-
855-
if render_transparent {
856-
out.push("transparent");
857-
}
858-
}
859-
if repr.simd() {
860-
out.push("simd");
861-
}
862-
let pack_s;
863-
if let Some(pack) = repr.pack {
864-
pack_s = format!("packed({})", pack.bytes());
865-
out.push(&pack_s);
866-
}
867-
let align_s;
868-
if let Some(align) = repr.align {
869-
align_s = format!("align({})", align.bytes());
870-
out.push(&align_s);
871-
}
872-
let int_s;
873-
if let Some(int) = repr.int {
874-
int_s = match int {
875-
IntegerType::Pointer(is_signed) => {
876-
format!("{}size", if is_signed { 'i' } else { 'u' })
877-
}
878-
IntegerType::Fixed(size, is_signed) => {
879-
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
880-
}
881-
};
882-
out.push(&int_s);
883-
}
884-
if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
825+
repr_attributes(tcx, cache, self.def_id()?, self.type_())
885826
}
886827

887828
pub fn is_doc_hidden(&self) -> bool {
@@ -893,6 +834,71 @@ impl Item {
893834
}
894835
}
895836

837+
pub(crate) fn repr_attributes(
838+
tcx: TyCtxt<'_>,
839+
cache: &Cache,
840+
def_id: DefId,
841+
item_type: ItemType,
842+
) -> Option<String> {
843+
use rustc_abi::IntegerType;
844+
845+
if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
846+
return None;
847+
}
848+
let adt = tcx.adt_def(def_id);
849+
let repr = adt.repr();
850+
let mut out = Vec::new();
851+
if repr.c() {
852+
out.push("C");
853+
}
854+
if repr.transparent() {
855+
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
856+
// field is public in case all fields are 1-ZST fields.
857+
let render_transparent = cache.document_private
858+
|| adt
859+
.all_fields()
860+
.find(|field| {
861+
let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
862+
tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
863+
.is_ok_and(|layout| !layout.is_1zst())
864+
})
865+
.map_or_else(
866+
|| adt.all_fields().any(|field| field.vis.is_public()),
867+
|field| field.vis.is_public(),
868+
);
869+
870+
if render_transparent {
871+
out.push("transparent");
872+
}
873+
}
874+
if repr.simd() {
875+
out.push("simd");
876+
}
877+
let pack_s;
878+
if let Some(pack) = repr.pack {
879+
pack_s = format!("packed({})", pack.bytes());
880+
out.push(&pack_s);
881+
}
882+
let align_s;
883+
if let Some(align) = repr.align {
884+
align_s = format!("align({})", align.bytes());
885+
out.push(&align_s);
886+
}
887+
let int_s;
888+
if let Some(int) = repr.int {
889+
int_s = match int {
890+
IntegerType::Pointer(is_signed) => {
891+
format!("{}size", if is_signed { 'i' } else { 'u' })
892+
}
893+
IntegerType::Fixed(size, is_signed) => {
894+
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
895+
}
896+
};
897+
out.push(&int_s);
898+
}
899+
if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
900+
}
901+
896902
#[derive(Clone, Debug)]
897903
pub(crate) enum ItemKind {
898904
ExternCrateItem {

src/librustdoc/html/render/mod.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1201,11 +1201,31 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) ->
12011201
})
12021202
}
12031203

1204+
struct CodeAttribute(String);
1205+
1206+
impl CodeAttribute {
1207+
fn render_into(self, w: &mut impl fmt::Write) {
1208+
write!(w, "<div class=\"code-attribute\">{}</div>", self.0).unwrap();
1209+
}
1210+
}
1211+
12041212
// When an attribute is rendered inside a <code> tag, it is formatted using
12051213
// a div to produce a newline after it.
12061214
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
12071215
for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
1208-
write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
1216+
CodeAttribute(attr).render_into(w);
1217+
}
1218+
}
1219+
1220+
/// used for type aliases to only render their `repr` attribute.
1221+
fn render_repr_attributes_in_code(
1222+
w: &mut impl fmt::Write,
1223+
cx: &Context<'_>,
1224+
def_id: DefId,
1225+
item_type: ItemType,
1226+
) {
1227+
if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
1228+
CodeAttribute(repr).render_into(w);
12091229
}
12101230
}
12111231

src/librustdoc/html/render/print_item.rs

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use super::{
2020
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
2121
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
2222
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
23-
render_impl, render_rightside, render_stability_since_raw,
23+
render_impl, render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
2424
render_stability_since_raw_with_extra, write_section_heading,
2525
};
2626
use crate::clean;
@@ -1290,12 +1290,30 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) ->
12901290
.render_into(cx, it, true, w)?;
12911291
}
12921292
clean::TypeAliasInnerType::Union { fields } => {
1293-
ItemUnion { cx, it, fields, generics: &t.generics, is_type_alias: true }
1294-
.render_into(w)?;
1293+
let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
1294+
let union_def_id = ty.ty_adt_def().unwrap().did();
1295+
1296+
ItemUnion {
1297+
cx,
1298+
it,
1299+
fields,
1300+
generics: &t.generics,
1301+
is_type_alias: true,
1302+
def_id: union_def_id,
1303+
}
1304+
.render_into(w)?;
12951305
}
12961306
clean::TypeAliasInnerType::Struct { ctor_kind, fields } => {
1297-
DisplayStruct { ctor_kind: *ctor_kind, generics: &t.generics, fields }
1298-
.render_into(cx, it, true, w)?;
1307+
let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
1308+
let struct_def_id = ty.ty_adt_def().unwrap().did();
1309+
1310+
DisplayStruct {
1311+
ctor_kind: *ctor_kind,
1312+
generics: &t.generics,
1313+
fields,
1314+
def_id: struct_def_id,
1315+
}
1316+
.render_into(cx, it, true, w)?;
12991317
}
13001318
}
13011319
} else {
@@ -1417,8 +1435,9 @@ item_template!(
14171435
fields: &'a [clean::Item],
14181436
generics: &'a clean::Generics,
14191437
is_type_alias: bool,
1438+
def_id: DefId,
14201439
},
1421-
methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items]
1440+
methods = [document, document_type_layout, render_assoc_items]
14221441
);
14231442

14241443
impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
@@ -1449,13 +1468,41 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
14491468
})
14501469
.peekable()
14511470
}
1471+
1472+
fn render_attributes_in_pre(&self) -> impl fmt::Display {
1473+
fmt::from_fn(move |f| {
1474+
if !self.is_type_alias {
1475+
for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) {
1476+
writeln!(f, "{a}")?;
1477+
}
1478+
} else {
1479+
// For now we only render `repr` attributes for type aliases.
1480+
if let Some(repr) = clean::repr_attributes(
1481+
self.cx.tcx(),
1482+
self.cx.cache(),
1483+
self.def_id,
1484+
ItemType::Union,
1485+
) {
1486+
writeln!(f, "{repr}")?;
1487+
};
1488+
}
1489+
Ok(())
1490+
})
1491+
}
14521492
}
14531493

14541494
fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display {
14551495
fmt::from_fn(|w| {
1456-
ItemUnion { cx, it, fields: &s.fields, generics: &s.generics, is_type_alias: false }
1457-
.render_into(w)
1458-
.unwrap();
1496+
ItemUnion {
1497+
cx,
1498+
it,
1499+
fields: &s.fields,
1500+
generics: &s.generics,
1501+
is_type_alias: false,
1502+
def_id: it.def_id().unwrap(),
1503+
}
1504+
.render_into(w)
1505+
.unwrap();
14591506
Ok(())
14601507
})
14611508
}
@@ -1502,7 +1549,12 @@ impl<'a> DisplayEnum<'a> {
15021549
let has_stripped_entries = variants_len != variants_count;
15031550

15041551
wrap_item(w, |w| {
1505-
render_attributes_in_code(w, it, cx);
1552+
if !is_type_alias {
1553+
render_attributes_in_code(w, it, cx);
1554+
} else {
1555+
// For now we only render `repr` attributes for type aliases.
1556+
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
1557+
}
15061558
write!(
15071559
w,
15081560
"{}enum {}{}{}",
@@ -1521,19 +1573,22 @@ impl<'a> DisplayEnum<'a> {
15211573
)
15221574
})?;
15231575

1524-
if !is_type_alias {
1576+
let def_id = it.item_id.expect_def_id();
1577+
let layout_def_id = if !is_type_alias {
15251578
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
1526-
}
1579+
def_id
1580+
} else {
1581+
self.def_id
1582+
};
15271583

15281584
if variants_count != 0 {
15291585
write!(w, "{}", item_variants(cx, it, self.variants, self.def_id))?;
15301586
}
1531-
let def_id = it.item_id.expect_def_id();
15321587
write!(
15331588
w,
15341589
"{}{}",
15351590
render_assoc_items(cx, it, def_id, AssocItemRender::All),
1536-
document_type_layout(cx, def_id)
1591+
document_type_layout(cx, layout_def_id)
15371592
)
15381593
}
15391594
}
@@ -1938,6 +1993,7 @@ struct DisplayStruct<'a> {
19381993
ctor_kind: Option<CtorKind>,
19391994
generics: &'a clean::Generics,
19401995
fields: &'a [clean::Item],
1996+
def_id: DefId,
19411997
}
19421998

19431999
impl<'a> DisplayStruct<'a> {
@@ -1949,7 +2005,12 @@ impl<'a> DisplayStruct<'a> {
19492005
w: &mut W,
19502006
) -> fmt::Result {
19512007
wrap_item(w, |w| {
1952-
render_attributes_in_code(w, it, cx);
2008+
if !is_type_alias {
2009+
render_attributes_in_code(w, it, cx);
2010+
} else {
2011+
// For now we only render `repr` attributes for type aliases.
2012+
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
2013+
}
19532014
write!(
19542015
w,
19552016
"{}",
@@ -1974,8 +2035,13 @@ impl<'a> DisplayStruct<'a> {
19742035

19752036
fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display {
19762037
fmt::from_fn(|w| {
1977-
DisplayStruct { ctor_kind: s.ctor_kind, generics: &s.generics, fields: s.fields.as_slice() }
1978-
.render_into(cx, it, false, w)
2038+
DisplayStruct {
2039+
ctor_kind: s.ctor_kind,
2040+
generics: &s.generics,
2041+
fields: s.fields.as_slice(),
2042+
def_id: it.def_id().unwrap(),
2043+
}
2044+
.render_into(cx, it, false, w)
19792045
})
19802046
}
19812047

tests/rustdoc/type-layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub type TypeAlias = X;
6161
pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>);
6262

6363
// Regression test for the rustdoc equivalent of #85103.
64-
//@ hasraw type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.'
64+
//@ 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.'
6565
pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>;
6666

6767
//@ !hasraw type_layout/trait.MyTrait.html 'Size: '

0 commit comments

Comments
 (0)