@@ -2964,6 +2964,10 @@ fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) {
2964
2964
write ! ( w, "<div class=\" code-attribute\" >{prefix}{attr}</div>" ) . unwrap ( ) ;
2965
2965
}
2966
2966
2967
+ /// Compute the *public* `#[repr]` of the item given by `DefId`.
2968
+ ///
2969
+ /// Read more about it here:
2970
+ /// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
2967
2971
fn repr_attribute < ' tcx > (
2968
2972
tcx : TyCtxt < ' tcx > ,
2969
2973
cache : & Cache ,
@@ -2975,25 +2979,59 @@ fn repr_attribute<'tcx>(
2975
2979
} ;
2976
2980
let repr = adt. repr ( ) ;
2977
2981
2982
+ let is_visible = |def_id| cache. document_hidden || !tcx. is_doc_hidden ( def_id) ;
2983
+ let is_public_field = |field : & ty:: FieldDef | {
2984
+ ( cache. document_private || field. vis . is_public ( ) ) && is_visible ( field. did )
2985
+ } ;
2986
+
2978
2987
if repr. transparent ( ) {
2979
- // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
2980
- // field is public in case all fields are 1-ZST fields.
2981
- let render_transparent = cache. document_private
2982
- || adt
2983
- . all_fields ( )
2984
- . find ( |field| {
2985
- let ty = field. ty ( tcx, ty:: GenericArgs :: identity_for_item ( tcx, field. did ) ) ;
2986
- tcx. layout_of ( ty:: TypingEnv :: post_analysis ( tcx, field. did ) . as_query_input ( ty) )
2987
- . is_ok_and ( |layout| !layout. is_1zst ( ) )
2988
- } )
2989
- . map_or_else (
2990
- || adt. all_fields ( ) . any ( |field| field. vis . is_public ( ) ) ,
2991
- |field| field. vis . is_public ( ) ,
2992
- ) ;
2988
+ // The transparent repr is public iff the non-1-ZST field is public and visible or
2989
+ // – in case all fields are 1-ZST fields — at least one field is public and visible.
2990
+ let is_public = ' is_public: {
2991
+ // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
2992
+ let var = adt. variant ( rustc_abi:: FIRST_VARIANT ) ; // the first and only variant
2993
+
2994
+ if !is_visible ( var. def_id ) {
2995
+ break ' is_public false ;
2996
+ }
2997
+
2998
+ // Side note: There can only ever be one or zero non-1-ZST fields.
2999
+ let non_1zst_field = var. fields . iter ( ) . find ( |field| {
3000
+ let ty = ty:: TypingEnv :: post_analysis ( tcx, field. did )
3001
+ . as_query_input ( tcx. type_of ( field. did ) . instantiate_identity ( ) ) ;
3002
+ tcx. layout_of ( ty) . is_ok_and ( |layout| !layout. is_1zst ( ) )
3003
+ } ) ;
3004
+
3005
+ match non_1zst_field {
3006
+ Some ( field) => is_public_field ( field) ,
3007
+ None => var. fields . is_empty ( ) || var. fields . iter ( ) . any ( is_public_field) ,
3008
+ }
3009
+ } ;
2993
3010
2994
3011
// Since the transparent repr can't have any other reprs or
2995
3012
// repr modifiers beside it, we can safely return early here.
2996
- return render_transparent. then ( || "#[repr(transparent)]" . into ( ) ) ;
3013
+ return is_public. then ( || "#[repr(transparent)]" . into ( ) ) ;
3014
+ }
3015
+
3016
+ // Fast path which avoids looking through the variants and fields in
3017
+ // the common case of no `#[repr]` or in the case of `#[repr(Rust)]`.
3018
+ // FIXME: This check is not very robust / forward compatible!
3019
+ if !repr. c ( )
3020
+ && !repr. simd ( )
3021
+ && repr. int . is_none ( )
3022
+ && repr. pack . is_none ( )
3023
+ && repr. align . is_none ( )
3024
+ {
3025
+ return None ;
3026
+ }
3027
+
3028
+ // The repr is public iff all components are public and visible.
3029
+ let is_public = adt
3030
+ . variants ( )
3031
+ . iter ( )
3032
+ . all ( |variant| is_visible ( variant. def_id ) && variant. fields . iter ( ) . all ( is_public_field) ) ;
3033
+ if !is_public {
3034
+ return None ;
2997
3035
}
2998
3036
2999
3037
let mut result = Vec :: < Cow < ' _ , _ > > :: new ( ) ;
@@ -3004,12 +3042,6 @@ fn repr_attribute<'tcx>(
3004
3042
if repr. simd ( ) {
3005
3043
result. push ( "simd" . into ( ) ) ;
3006
3044
}
3007
- if let Some ( pack) = repr. pack {
3008
- result. push ( format ! ( "packed({})" , pack. bytes( ) ) . into ( ) ) ;
3009
- }
3010
- if let Some ( align) = repr. align {
3011
- result. push ( format ! ( "align({})" , align. bytes( ) ) . into ( ) ) ;
3012
- }
3013
3045
if let Some ( int) = repr. int {
3014
3046
let prefix = if int. is_signed ( ) { 'i' } else { 'u' } ;
3015
3047
let int = match int {
@@ -3021,5 +3053,13 @@ fn repr_attribute<'tcx>(
3021
3053
result. push ( int. into ( ) ) ;
3022
3054
}
3023
3055
3056
+ // Render modifiers last.
3057
+ if let Some ( pack) = repr. pack {
3058
+ result. push ( format ! ( "packed({})" , pack. bytes( ) ) . into ( ) ) ;
3059
+ }
3060
+ if let Some ( align) = repr. align {
3061
+ result. push ( format ! ( "align({})" , align. bytes( ) ) . into ( ) ) ;
3062
+ }
3063
+
3024
3064
( !result. is_empty ( ) ) . then ( || format ! ( "#[repr({})]" , result. join( ", " ) ) . into ( ) )
3025
3065
}
0 commit comments