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:
commit
a39d5134cd
15 changed files with 350 additions and 299 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
|
|||
5
tests/rustdoc/auxiliary/ext-repr.rs
Normal file
5
tests/rustdoc/auxiliary/ext-repr.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#[repr(i8)]
|
||||
pub enum ReprI8 {
|
||||
Var0,
|
||||
Var1,
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 {}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue