about summary refs log tree commit diff
path: root/src/librustdoc/clean
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-10-14 19:22:16 +0200
committerGitHub <noreply@github.com>2023-10-14 19:22:16 +0200
commit4dd4d9b489d71b8020eedea1001ad2b0904601be (patch)
tree16026c52838f82fa41c454cb4759a71682c68e17 /src/librustdoc/clean
parent0233608c67b1c89050b2aa0a30d6c5f703f325f4 (diff)
parent64fa12a4fb1447e3368ae2cd08cf75ea576997ea (diff)
Rollup merge of #115439 - fmease:rustdoc-priv-repr-transparent-heuristic, r=GuillaumeGomez
rustdoc: hide `#[repr(transparent)]` if it isn't part of the public ABI

Fixes #90435.

This hides `#[repr(transparent)]` when the non-1-ZST field the struct is "transparent" over is private.

CC `@RalfJung`

Tentatively nominating it for the release notes, feel free to remove the nomination.
`@rustbot` label needs-fcp relnotes A-rustdoc-ui
Diffstat (limited to 'src/librustdoc/clean')
-rw-r--r--src/librustdoc/clean/types.rs51
1 files changed, 36 insertions, 15 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 517a51867cf..2a54266676d 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -713,12 +713,16 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
+    pub(crate) fn attributes(
+        &self,
+        tcx: TyCtxt<'_>,
+        cache: &Cache,
+        keep_as_is: bool,
+    ) -> Vec<String> {
         const ALLOWED_ATTRIBUTES: &[Symbol] =
-            &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
+            &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
 
         use rustc_abi::IntegerType;
-        use rustc_middle::ty::ReprFlags;
 
         let mut attrs: Vec<String> = self
             .attrs
@@ -739,20 +743,38 @@ impl Item {
                 }
             })
             .collect();
-        if let Some(def_id) = self.def_id() &&
-            !def_id.is_local() &&
-            // This check is needed because `adt_def` will panic if not a compatible type otherwise...
-            matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
+        if !keep_as_is
+            && let Some(def_id) = self.def_id()
+            && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
         {
-            let repr = tcx.adt_def(def_id).repr();
+            let adt = tcx.adt_def(def_id);
+            let repr = adt.repr();
             let mut out = Vec::new();
-            if repr.flags.contains(ReprFlags::IS_C) {
+            if repr.c() {
                 out.push("C");
             }
-            if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
-                out.push("transparent");
+            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(tcx.param_env(field.did).and(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.flags.contains(ReprFlags::IS_SIMD) {
+            if repr.simd() {
                 out.push("simd");
             }
             let pack_s;
@@ -777,10 +799,9 @@ impl Item {
                 };
                 out.push(&int_s);
             }
-            if out.is_empty() {
-                return Vec::new();
+            if !out.is_empty() {
+                attrs.push(format!("#[repr({})]", out.join(", ")));
             }
-            attrs.push(format!("#[repr({})]", out.join(", ")));
         }
         attrs
     }