Rollup merge of #116882 - fmease:rustdoc-generalized-priv-repr-heuristic, r=rustdoc

rustdoc: hide `#[repr]` if it isn't part of the public ABI

> [!IMPORTANT]
> Temporarily stacked on top of PR https://github.com/rust-lang/rust/pull/146527; only the last commit is relevant!

Follow-up to rust-lang/rust#115439.
Unblocks rust-lang/rust#116743, CC ``@dtolnay.``

Fixes rust-lang/rust#66401.
Fixes rust-lang/rust#128364.
Fixes rust-lang/rust#137440.

Only display the representation `#[repr(REPR)]` (where `REPR` is not `Rust` or `transparent`) of a given type if none of its variants (incl. the synthetic variants of structs) are `#[doc(hidden)]` and all of its fields are public and not `#[doc(hidden)]` since it's likely not meant to be considered part of the public ABI otherwise.

`--document-{private,hidden}-items` works as expected in this context, too.

Moreover, we now also factor in the presence of `#[doc(hidden)]` when checking whether to show `repr(transparent)` or not.
This commit is contained in:
Matthias Krüger 2025-09-25 18:15:06 +02:00 committed by GitHub
commit a39d5134cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 350 additions and 299 deletions

View file

@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
to automatically go to the first result.
## `#[repr(transparent)]`: Documenting the transparent representation
## `#[repr(...)]`: Documenting the representation of a type
Generally, rustdoc only displays the representation of a given type if none of its variants are
`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely
not meant to be considered part of the public ABI otherwise.
Note that there's no way to overwrite that heuristic and force rustdoc to show the representation
regardless.
### `#[repr(transparent)]`
You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
in the [Rustonomicon][repr-trans-nomicon].
Since this representation is only considered part of the public ABI if the single field with non-trivial
size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
size or alignment is public and if the documentation does not state otherwise, rustdoc helpfully displays
the attribute if and only if the non-1-ZST field is public and not `#[doc(hidden)]` or
in case all fields are 1-ZST fields — at least one field is public and not `#[doc(hidden)]`.
The term *1-ZST* refers to types that are one-aligned and zero-sized.
It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
if one wishes to declare the representation as private even if the non-1-ZST field is public.
However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
Therefore, if you would like to do so, you should always write it down in prose independently of whether
Therefore, if you would like to do so, you should always write that down in prose independently of whether
you use `cfg_attr` or not.
[repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation

View file

@ -794,50 +794,6 @@ impl Item {
Some(tcx.visibility(def_id))
}
/// Get a list of attributes excluding `#[repr]` to display.
///
/// Only used by the HTML output-format.
fn attributes_without_repr(&self) -> Vec<String> {
self.attrs
.other_attrs
.iter()
.filter_map(|attr| match attr {
hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
Some(format!("#[unsafe(link_section = \"{name}\")]"))
}
hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
Some("#[unsafe(no_mangle)]".to_string())
}
hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
Some(format!("#[unsafe(export_name = \"{name}\")]"))
}
hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
Some("#[non_exhaustive]".to_string())
}
_ => None,
})
.collect()
}
/// Get a list of attributes to display on this item.
///
/// Only used by the HTML output-format.
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
let mut attrs = self.attributes_without_repr();
if let Some(repr_attr) = self.repr(tcx, cache) {
attrs.push(repr_attr);
}
attrs
}
/// Returns a stringified `#[repr(...)]` attribute.
///
/// Only used by the HTML output-format.
pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
repr_attributes(tcx, cache, self.def_id()?, self.type_())
}
pub fn is_doc_hidden(&self) -> bool {
self.attrs.is_doc_hidden()
}
@ -847,74 +803,6 @@ impl Item {
}
}
/// Return a string representing the `#[repr]` attribute if present.
///
/// Only used by the HTML output-format.
pub(crate) fn repr_attributes(
tcx: TyCtxt<'_>,
cache: &Cache,
def_id: DefId,
item_type: ItemType,
) -> 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
|| 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 {

View file

@ -51,7 +51,9 @@ use askama::Template;
use itertools::Either;
use rustc_ast::join_path_syms;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
use rustc_hir as hir;
use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
use rustc_middle::ty::print::PrintTraitRefExt;
@ -1310,43 +1312,6 @@ fn render_assoc_item(
})
}
struct CodeAttribute(String);
fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) {
write!(
w,
"<div class=\"code-attribute\">{prefix}{attr}</div>",
prefix = prefix,
attr = code_attr.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,
prefix: &str,
cx: &Context<'_>,
) {
for attr in it.attributes(cx.tcx(), cx.cache()) {
render_code_attribute(prefix, CodeAttribute(attr), 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) {
render_code_attribute("", CodeAttribute(repr), w);
}
}
#[derive(Copy, Clone)]
enum AssocItemLink<'a> {
Anchor(Option<&'a str>),
@ -2959,3 +2924,142 @@ fn render_call_locations<W: fmt::Write>(
w.write_str("</div>")
}
fn render_attributes_in_code(
w: &mut impl fmt::Write,
item: &clean::Item,
prefix: &str,
cx: &Context<'_>,
) {
for attr in &item.attrs.other_attrs {
let hir::Attribute::Parsed(kind) = attr else { continue };
let attr = match kind {
AttributeKind::LinkSection { name, .. } => {
Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
}
AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
AttributeKind::ExportName { name, .. } => {
Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
}
AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
_ => continue,
};
render_code_attribute(prefix, attr.as_ref(), w);
}
if let Some(def_id) = item.def_id()
&& let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id)
{
render_code_attribute(prefix, &repr, w);
}
}
fn render_repr_attribute_in_code(w: &mut impl fmt::Write, cx: &Context<'_>, def_id: DefId) {
if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) {
render_code_attribute("", &repr, w);
}
}
fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) {
write!(w, "<div class=\"code-attribute\">{prefix}{attr}</div>").unwrap();
}
/// Compute the *public* `#[repr]` of the item given by `DefId`.
///
/// Read more about it here:
/// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
fn repr_attribute<'tcx>(
tcx: TyCtxt<'tcx>,
cache: &Cache,
def_id: DefId,
) -> Option<Cow<'static, str>> {
let adt = match tcx.def_kind(def_id) {
DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id),
_ => return None,
};
let repr = adt.repr();
let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id);
let is_public_field = |field: &ty::FieldDef| {
(cache.document_private || field.vis.is_public()) && is_visible(field.did)
};
if repr.transparent() {
// The transparent repr is public iff the non-1-ZST field is public and visible or
// in case all fields are 1-ZST fields — at least one field is public and visible.
let is_public = 'is_public: {
// `#[repr(transparent)]` can only be applied to structs and single-variant enums.
let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant
if !is_visible(var.def_id) {
break 'is_public false;
}
// Side note: There can only ever be one or zero non-1-ZST fields.
let non_1zst_field = var.fields.iter().find(|field| {
let ty = ty::TypingEnv::post_analysis(tcx, field.did)
.as_query_input(tcx.type_of(field.did).instantiate_identity());
tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst())
});
match non_1zst_field {
Some(field) => is_public_field(field),
None => var.fields.is_empty() || var.fields.iter().any(is_public_field),
}
};
// Since the transparent repr can't have any other reprs or
// repr modifiers beside it, we can safely return early here.
return is_public.then(|| "#[repr(transparent)]".into());
}
// Fast path which avoids looking through the variants and fields in
// the common case of no `#[repr]` or in the case of `#[repr(Rust)]`.
// FIXME: This check is not very robust / forward compatible!
if !repr.c()
&& !repr.simd()
&& repr.int.is_none()
&& repr.pack.is_none()
&& repr.align.is_none()
{
return None;
}
// The repr is public iff all components are public and visible.
let is_public = adt
.variants()
.iter()
.all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field));
if !is_public {
return None;
}
let mut result = Vec::<Cow<'_, _>>::new();
if repr.c() {
result.push("C".into());
}
if repr.simd() {
result.push("simd".into());
}
if let Some(int) = repr.int {
let prefix = if int.is_signed() { 'i' } else { 'u' };
let int = match int {
rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"),
rustc_abi::IntegerType::Fixed(int, _) => {
format!("{prefix}{}", int.size().bytes() * 8)
}
};
result.push(int.into());
}
// Render modifiers last.
if let Some(pack) = repr.pack {
result.push(format!("packed({})", pack.bytes()).into());
}
if let Some(align) = repr.align {
result.push(format!("align({})", align.bytes()).into());
}
(!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into())
}

View file

@ -21,7 +21,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_impl,
render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
render_repr_attribute_in_code, render_rightside, render_stability_since_raw,
render_stability_since_raw_with_extra, write_section_heading,
};
use crate::clean;
@ -1555,7 +1555,7 @@ impl<'clean> DisplayEnum<'clean> {
wrap_item(w, |w| {
if is_type_alias {
// For now the only attributes we render for type aliases are `repr` attributes.
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
render_repr_attribute_in_code(w, cx, self.def_id);
} else {
render_attributes_in_code(w, it, "", cx);
}
@ -2017,7 +2017,7 @@ impl<'a> DisplayStruct<'a> {
wrap_item(w, |w| {
if is_type_alias {
// For now the only attributes we render for type aliases are `repr` attributes.
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
render_repr_attribute_in_code(w, cx, self.def_id);
} else {
render_attributes_in_code(w, it, "", cx);
}
@ -2371,7 +2371,7 @@ fn render_union(
fmt::from_fn(move |mut f| {
if is_type_alias {
// For now the only attributes we render for type aliases are `repr` attributes.
render_repr_attributes_in_code(f, cx, def_id, ItemType::Union);
render_repr_attribute_in_code(f, cx, def_id);
} else {
render_attributes_in_code(f, it, "", cx);
}

View file

@ -459,10 +459,10 @@ pub fn safe_fn() {}
#[repr(C)]
pub struct WithGenerics<T: TraitWithNoDocblocks, S = String, E = WhoLetTheDogOut, P = i8> {
s: S,
t: T,
e: E,
p: P,
pub s: S,
pub t: T,
pub e: E,
pub p: P,
}
pub struct StructWithPublicUndocumentedFields {

View file

@ -1,8 +0,0 @@
#![crate_name = "foo"]
//@ has 'foo/fn.f.html'
//@ has - //*[@'class="code-attribute"]' '#[unsafe(export_name = "f")]'
//@ has - //*[@'class="rust item-decl"]' 'pub fn f()'
#[unsafe(export_name = "\
f")]
pub fn f() {}

View file

@ -9,6 +9,18 @@ pub extern "C" fn f() {}
#[unsafe(export_name = "bar")]
pub extern "C" fn g() {}
//@ has foo/fn.escape_special.html '//*[@class="code-attribute"]' \
// '#[unsafe(export_name = "\n\"\n")]'
#[unsafe(export_name = "\n\"
")]
pub extern "C" fn escape_special() {}
// issue: <https://github.com/rust-lang/rust/issues/142835>
//@ has foo/fn.escape_html.html '//*[@class="code-attribute"]' \
// '#[unsafe(export_name = "<script>alert()</script>")]'
#[unsafe(export_name = "<script>alert()</script>")]
pub extern "C" fn escape_html() {}
//@ has foo/fn.example.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]'
#[unsafe(link_section = ".text")]
pub extern "C" fn example() {}

View file

@ -0,0 +1,5 @@
#[repr(i8)]
pub enum ReprI8 {
Var0,
Var1,
}

View file

@ -1,7 +1,20 @@
// Ensure that we render attributes on inlined cross-crate re-exported items.
// issue: <https://github.com/rust-lang/rust/issues/144004>
//@ aux-crate:attributes=attributes.rs
//@ edition:2021
#![crate_name = "user"]
//@ has 'user/struct.NonExhaustive.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]'
//@ has 'user/fn.no_mangle.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
pub use attributes::no_mangle;
//@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \
// '#[unsafe(link_section = ".here")]'
pub use attributes::link_section;
//@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \
// '#[unsafe(export_name = "exonym")]'
pub use attributes::export_name;
//@ has 'user/struct.NonExhaustive.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
pub use attributes::NonExhaustive;

View file

@ -1,2 +1,11 @@
#[unsafe(no_mangle)]
pub fn no_mangle() {}
#[unsafe(link_section = ".here")]
pub fn link_section() {}
#[unsafe(export_name = "exonym")]
pub fn export_name() {}
#[non_exhaustive]
pub struct NonExhaustive;

View file

@ -1,42 +0,0 @@
#![feature(repr_simd)]
#[repr(C, align(8))]
pub struct ReprC {
field: u8,
}
#[repr(simd, packed(2))]
pub struct ReprSimd {
field: [u8; 1],
}
#[repr(transparent)]
pub struct ReprTransparent {
pub field: u8,
}
#[repr(isize)]
pub enum ReprIsize {
Bla,
}
#[repr(u8)]
pub enum ReprU8 {
Bla,
}
#[repr(transparent)] // private
pub struct ReprTransparentPrivField {
field: u32, // non-1-ZST field
}
#[repr(transparent)] // public
pub struct ReprTransparentPriv1ZstFields {
marker0: Marker,
pub main: u64, // non-1-ZST field
marker1: Marker,
}
#[repr(transparent)] // private
pub struct ReprTransparentPrivFieldPub1ZstFields {
main: [u16; 0], // non-1-ZST field
pub marker: Marker,
}
pub struct Marker; // 1-ZST

View file

@ -1,40 +0,0 @@
// Regression test for <https://github.com/rust-lang/rust/issues/110698>.
// This test ensures that the re-exported items still have the `#[repr(...)]` attribute.
//@ aux-build:repr.rs
#![crate_name = "foo"]
extern crate repr;
//@ has 'foo/struct.ReprC.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
pub use repr::ReprC;
//@ has 'foo/struct.ReprSimd.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
pub use repr::ReprSimd;
//@ has 'foo/struct.ReprTransparent.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
pub use repr::ReprTransparent;
//@ has 'foo/enum.ReprIsize.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
pub use repr::ReprIsize;
//@ has 'foo/enum.ReprU8.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
pub use repr::ReprU8;
// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
// Check that we show `#[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.
//@ has 'foo/struct.ReprTransparentPrivField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
pub use repr::ReprTransparentPrivField;
//@ has 'foo/struct.ReprTransparentPriv1ZstFields.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
pub use repr::ReprTransparentPriv1ZstFields;
//@ has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
pub use repr::ReprTransparentPrivFieldPub1ZstFields;

View file

@ -1,14 +0,0 @@
#[unsafe(no_mangle)]
pub fn f0() {}
#[unsafe(link_section = ".here")]
pub fn f1() {}
#[unsafe(export_name = "f2export")]
pub fn f2() {}
#[repr(u8)]
pub enum T0 { V1 }
#[non_exhaustive]
pub enum T1 {}

View file

@ -1,20 +0,0 @@
//@ aux-build: reexports-attrs.rs
#![crate_name = "foo"]
extern crate reexports_attrs;
//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
pub use reexports_attrs::f0;
//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]'
pub use reexports_attrs::f1;
//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]'
pub use reexports_attrs::f2;
//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]'
pub use reexports_attrs::T0;
//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
pub use reexports_attrs::T1;

View file

@ -1,29 +1,163 @@
// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
// Check that we show `#[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.
// Test the rendering of `#[repr]` on ADTs.
#![feature(repr_simd)] // only used for the `ReprSimd` test case
// Check the "local case" (HIR cleaning) //
// Don't render the default repr which is `Rust`.
//@ has 'repr/struct.ReprDefault.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]'
pub struct ReprDefault;
// Don't render the `Rust` repr — even if given explicitly — since it's the default.
//@ has 'repr/struct.ReprRust.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]'
#[repr(Rust)] // omitted
pub struct ReprRust;
//@ has 'repr/struct.ReprCPubFields.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
#[repr(C)] // public
pub struct ReprCPubFields {
pub a: u32,
pub b: u32,
}
//@ has 'repr/struct.ReprCPrivField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
#[repr(C)] // private...
pub struct ReprCPrivField {
a: u32, // ...since this is private
pub b: u32,
}
//@ has 'repr/enum.ReprIsize.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
#[repr(isize)] // public
pub enum ReprIsize {
Bla,
}
//@ has 'repr/enum.ReprU32HiddenVariant.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32)]'
#[repr(u32)] // private...
pub enum ReprU32HiddenVariant {
#[doc(hidden)]
Hidden, // ...since this is hidden
Public,
}
//@ has 'repr/struct.ReprAlignHiddenField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(align(4))]'
#[repr(align(4))] // private...
pub struct ReprAlignHiddenField {
#[doc(hidden)]
pub hidden: i16, // ...since this field is hidden
}
//@ has 'repr/struct.ReprSimd.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
#[repr(simd, packed(2))] // public
pub struct ReprSimd {
pub field: [u8; 1],
}
//@ has 'repr/enum.ReprU32Align.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32, align(8))]'
#[repr(u32, align(8))] // public
pub enum ReprU32Align {
Variant(u16),
}
//@ has 'repr/enum.ReprCHiddenVariantField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
#[repr(C)] // private...
pub enum ReprCHiddenVariantField {
Variant { #[doc(hidden)] field: () }, //...since this field is hidden
}
//@ has 'repr/struct.ReprTransparentPrivField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // private
#[repr(transparent)] // private...
pub struct ReprTransparentPrivField {
field: u32, // non-1-ZST field
field: u32, // ...since the non-1-ZST field is private
}
//@ has 'repr/struct.ReprTransparentPriv1ZstFields.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // public
#[repr(transparent)] // public...
pub struct ReprTransparentPriv1ZstFields {
marker0: Marker,
pub main: u64, // non-1-ZST field
pub main: u64, // ...since the non-1-ZST field is public and visible
marker1: Marker,
} // the two private 1-ZST fields don't matter
//@ has 'repr/struct.ReprTransparentPrivFieldPub1ZstField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // private...
pub struct ReprTransparentPrivFieldPub1ZstField {
main: [u16; 0], // ...since the non-1-ZST field is private
pub marker: Marker, // this public 1-ZST field doesn't matter
}
//@ has 'repr/struct.ReprTransparentPub1ZstField.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // public
#[repr(transparent)] // public...
pub struct ReprTransparentPub1ZstField {
marker0: Marker,
pub marker1: Marker,
marker0: Marker, // ...since we don't have a non-1-ZST field...
pub marker1: Marker, // ...and this field is public and visible
}
//@ has 'repr/struct.ReprTransparentUnitStruct.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // public
pub struct ReprTransparentUnitStruct;
//@ has 'repr/enum.ReprTransparentEnumUnitVariant.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // public
pub enum ReprTransparentEnumUnitVariant {
Variant,
}
//@ has 'repr/enum.ReprTransparentEnumHiddenUnitVariant.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // private
pub enum ReprTransparentEnumHiddenUnitVariant {
#[doc(hidden)] Variant(u32),
}
//@ has 'repr/enum.ReprTransparentEnumPub1ZstField.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // public...
pub enum ReprTransparentEnumPub1ZstField {
Variant {
field: u64, // ...since the non-1-ZST field is public
#[doc(hidden)]
marker: Marker, // this hidden 1-ZST field doesn't matter
},
}
//@ has 'repr/enum.ReprTransparentEnumHidden1ZstField.html'
//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[repr(transparent)] // private...
pub enum ReprTransparentEnumHidden1ZstField {
Variant {
#[doc(hidden)]
field: u64, // ...since the non-1-ZST field is public
},
}
struct Marker; // 1-ZST
// Check the "extern case" (middle cleaning) //
// Internally, HIR and middle cleaning share `#[repr]` rendering.
// Thus we'll only test the very basics in this section.
//@ aux-build: ext-repr.rs
extern crate ext_repr as ext;
// Regression test for <https://github.com/rust-lang/rust/issues/110698>.
//@ has 'repr/enum.ReprI8.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(i8)]'
pub use ext::ReprI8;