@@ -713,17 +713,15 @@ impl Item {
713713        Some ( tcx. visibility ( def_id) ) 
714714    } 
715715
716-     pub ( crate )  fn  attributes ( 
716+     pub ( crate )  fn  attributes < ' tcx > ( 
717717        & self , 
718-         tcx :  TyCtxt < ' _ > , 
718+         tcx :  TyCtxt < ' tcx > , 
719719        cache :  & Cache , 
720720        keep_as_is :  bool , 
721721    )  -> Vec < String >  { 
722722        const  ALLOWED_ATTRIBUTES :  & [ Symbol ]  =
723723            & [ sym:: export_name,  sym:: link_section,  sym:: no_mangle,  sym:: non_exhaustive] ; 
724724
725-         use  rustc_abi:: IntegerType ; 
726- 
727725        let  mut  attrs:  Vec < String >  = self 
728726            . attrs 
729727            . other_attrs 
@@ -743,67 +741,121 @@ impl Item {
743741                } 
744742            } ) 
745743            . collect ( ) ; 
746-         if  !keep_as_is
747-             && let  Some ( def_id)  = self . def_id ( ) 
748-             && let  ItemType :: Struct  | ItemType :: Enum  | ItemType :: Union  = self . type_ ( ) 
749-         { 
750-             let  adt = tcx. adt_def ( def_id) ; 
751-             let  repr = adt. repr ( ) ; 
752-             let  mut  out = Vec :: new ( ) ; 
753-             if  repr. c ( )  { 
754-                 out. push ( "C" ) ; 
755-             } 
756-             if  repr. transparent ( )  { 
757-                 // Render `repr(transparent)` iff the non-1-ZST field is public or at least one 
758-                 // field is public in case all fields are 1-ZST fields. 
759-                 let  render_transparent = cache. document_private 
760-                     || adt
761-                         . all_fields ( ) 
762-                         . find ( |field| { 
763-                             let  ty =
764-                                 field. ty ( tcx,  ty:: GenericArgs :: identity_for_item ( tcx,  field. did ) ) ; 
765-                             tcx. layout_of ( tcx. param_env ( field. did ) . and ( ty) ) 
766-                                 . is_ok_and ( |layout| !layout. is_1zst ( ) ) 
767-                         } ) 
768-                         . map_or_else ( 
769-                             || adt. all_fields ( ) . any ( |field| field. vis . is_public ( ) ) , 
770-                             |field| field. vis . is_public ( ) , 
771-                         ) ; 
772744
773-                 if  render_transparent { 
774-                     out. push ( "transparent" ) ; 
775-                 } 
776-             } 
777-             if  repr. simd ( )  { 
778-                 out. push ( "simd" ) ; 
779-             } 
780-             let  pack_s; 
781-             if  let  Some ( pack)  = repr. pack  { 
782-                 pack_s = format ! ( "packed({})" ,  pack. bytes( ) ) ; 
783-                 out. push ( & pack_s) ; 
784-             } 
785-             let  align_s; 
786-             if  let  Some ( align)  = repr. align  { 
787-                 align_s = format ! ( "align({})" ,  align. bytes( ) ) ; 
788-                 out. push ( & align_s) ; 
789-             } 
790-             let  int_s; 
791-             if  let  Some ( int)  = repr. int  { 
792-                 int_s = match  int { 
793-                     IntegerType :: Pointer ( is_signed)  => { 
794-                         format ! ( "{}size" ,  if  is_signed {  'i'  }  else {  'u'  } ) 
745+         if  !keep_as_is && let  Some ( repr)  = self . repr ( tcx,  cache)  { 
746+             attrs. push ( repr) ; 
747+         } 
748+ 
749+         attrs
750+     } 
751+ 
752+     /// Compute the *public* `#[repr]` of this item. 
753+ /// 
754+ /// Read more about it here: 
755+ /// https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type 
756+ fn  repr < ' tcx > ( & self ,  tcx :  TyCtxt < ' tcx > ,  cache :  & Cache )  -> Option < String >  { 
757+         let  def_id = self . def_id ( ) ?; 
758+         let  ( ItemType :: Struct  | ItemType :: Enum  | ItemType :: Union )  = self . type_ ( )  else  { 
759+             return  None ; 
760+         } ; 
761+ 
762+         let  adt = tcx. adt_def ( def_id) ; 
763+         let  repr = adt. repr ( ) ; 
764+ 
765+         let  is_visible = |def_id| cache. document_hidden  || !tcx. is_doc_hidden ( def_id) ; 
766+         let  is_field_public =
767+             |field :  & ' tcx  ty:: FieldDef | field. vis . is_public ( )  && is_visible ( field. did ) ; 
768+ 
769+         if  repr. transparent ( )  { 
770+             // `repr(transparent)` is public iff the non-1-ZST field is public or 
771+             // at least one field is public in case all fields are 1-ZST fields. 
772+             let  is_public = cache. document_private 
773+                 || adt. variants ( ) . iter ( ) . all ( |variant| { 
774+                     if  !is_visible ( variant. def_id )  { 
775+                         return  false ; 
795776                    } 
796-                     IntegerType :: Fixed ( size,  is_signed)  => { 
797-                         format ! ( "{}{}" ,  if  is_signed {  'i'  }  else {  'u'  } ,  size. size( ) . bytes( )  *  8 ) 
777+ 
778+                     let  field = variant. fields . iter ( ) . find ( |field| { 
779+                         let  args = ty:: GenericArgs :: identity_for_item ( tcx,  field. did ) ; 
780+                         let  ty = field. ty ( tcx,  args) ; 
781+                         tcx. layout_of ( tcx. param_env ( field. did ) . and ( ty) ) 
782+                             . is_ok_and ( |layout| !layout. is_1zst ( ) ) 
783+                     } ) ; 
784+ 
785+                     if  let  Some ( field)  = field { 
786+                         return  is_field_public ( field) ; 
798787                    } 
799-                 } ; 
800-                 out. push ( & int_s) ; 
801-             } 
802-             if  !out. is_empty ( )  { 
803-                 attrs. push ( format ! ( "#[repr({})]" ,  out. join( ", " ) ) ) ; 
804-             } 
788+ 
789+                     adt. variants ( ) . iter ( ) . all ( |variant| { 
790+                         variant. fields . is_empty ( )  || variant. fields . iter ( ) . any ( is_field_public) 
791+                     } ) 
792+                 } ) ; 
793+ 
794+             // Since `repr(transparent)` can't have any other reprs or 
795+             // repr modifiers beside it, we can safely return early here. 
796+             return  is_public. then ( || "#[repr(transparent)]" . into ( ) ) ; 
805797        } 
806-         attrs
798+ 
799+         // Fast path that avoids looking at the variants and fields. 
800+         if  !repr. c ( ) 
801+             && !repr. simd ( ) 
802+             && repr. int . is_none ( ) 
803+             && repr. pack . is_none ( ) 
804+             && repr. align . is_none ( ) 
805+         { 
806+             return  None ; 
807+         } 
808+ 
809+         let  is_public = cache. document_private 
810+             || if  adt. is_enum ( )  { 
811+                 // FIXME(fmease): Should we take the visibility of fields of variants into account? 
812+                 // FIXME(fmease): `any` or `all`? 
813+                 adt. variants ( ) . is_empty ( ) 
814+                     || adt. variants ( ) . iter ( ) . any ( |variant| is_visible ( variant. def_id ) ) 
815+             }  else  { 
816+                 // FIXME(fmease): `all` or `any`? 
817+                 adt. all_fields ( ) . all ( is_field_public) 
818+             } ; 
819+         if  !is_public { 
820+             return  None ; 
821+         } 
822+ 
823+         let  mut  result = Vec :: new ( ) ; 
824+ 
825+         if  repr. c ( )  { 
826+             result. push ( "C" ) ; 
827+         } 
828+         if  repr. simd ( )  { 
829+             result. push ( "simd" ) ; 
830+         } 
831+         let  int_s; 
832+         if  let  Some ( int)  = repr. int  { 
833+             int_s = match  int { 
834+                 rustc_abi:: IntegerType :: Pointer ( is_signed)  => { 
835+                     format ! ( "{}size" ,  if  is_signed {  'i'  }  else {  'u'  } ) 
836+                 } 
837+                 rustc_abi:: IntegerType :: Fixed ( size,  is_signed)  => { 
838+                     format ! ( "{}{}" ,  if  is_signed {  'i'  }  else {  'u'  } ,  size. size( ) . bytes( )  *  8 ) 
839+                 } 
840+             } ; 
841+             result. push ( & int_s) ; 
842+         } 
843+         let  pack_s; 
844+         if  let  Some ( pack)  = repr. pack  { 
845+             pack_s = format ! ( "packed({})" ,  pack. bytes( ) ) ; 
846+             result. push ( & pack_s) ; 
847+         } 
848+         let  align_s; 
849+         if  let  Some ( align)  = repr. align  { 
850+             align_s = format ! ( "align({})" ,  align. bytes( ) ) ; 
851+             result. push ( & align_s) ; 
852+         } 
853+ 
854+         if  result. is_empty ( )  { 
855+             return  None ; 
856+         } 
857+ 
858+         Some ( format ! ( "#[repr({})]" ,  result. join( ", " ) ) ) 
807859    } 
808860
809861    pub  fn  is_doc_hidden ( & self )  -> bool  { 
0 commit comments