@@ -51,7 +51,9 @@ use askama::Template;
5151use itertools:: Either ;
5252use rustc_ast:: join_path_syms;
5353use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
54- use rustc_hir:: attrs:: { DeprecatedSince , Deprecation } ;
54+ use rustc_hir as hir;
55+ use rustc_hir:: attrs:: { AttributeKind , DeprecatedSince , Deprecation } ;
56+ use rustc_hir:: def:: DefKind ;
5557use rustc_hir:: def_id:: { DefId , DefIdSet } ;
5658use rustc_hir:: { ConstStability , Mutability , RustcVersion , StabilityLevel , StableSince } ;
5759use rustc_middle:: ty:: print:: PrintTraitRefExt ;
@@ -1310,38 +1312,6 @@ fn render_assoc_item(
13101312 } )
13111313}
13121314
1313- struct CodeAttribute ( String ) ;
1314-
1315- fn render_code_attribute ( prefix : & str , code_attr : CodeAttribute , w : & mut impl fmt:: Write ) {
1316- write ! (
1317- w,
1318- "<div class=\" code-attribute\" >{prefix}{attr}</div>" ,
1319- prefix = prefix,
1320- attr = code_attr. 0
1321- )
1322- . unwrap ( ) ;
1323- }
1324-
1325- // When an attribute is rendered inside a <code> tag, it is formatted using
1326- // a div to produce a newline after it.
1327- fn render_attributes_in_code (
1328- w : & mut impl fmt:: Write ,
1329- it : & clean:: Item ,
1330- prefix : & str ,
1331- cx : & Context < ' _ > ,
1332- ) {
1333- for attr in it. attributes ( cx. tcx ( ) , cx. cache ( ) ) {
1334- render_code_attribute ( prefix, CodeAttribute ( attr) , w) ;
1335- }
1336- }
1337-
1338- /// used for type aliases to only render their `repr` attribute.
1339- fn render_repr_attribute_in_code ( w : & mut impl fmt:: Write , cx : & Context < ' _ > , def_id : DefId ) {
1340- if let Some ( repr) = clean:: repr_attribute ( cx. tcx ( ) , cx. cache ( ) , def_id) {
1341- render_code_attribute ( "" , CodeAttribute ( repr) , w) ;
1342- }
1343- }
1344-
13451315#[ derive( Copy , Clone ) ]
13461316enum AssocItemLink < ' a > {
13471317 Anchor ( Option < & ' a str > ) ,
@@ -2927,3 +2897,148 @@ fn render_call_locations<W: fmt::Write>(
29272897
29282898 w. write_str ( "</div>" )
29292899}
2900+
2901+ fn render_attributes_in_code (
2902+ w : & mut impl fmt:: Write ,
2903+ it : & clean:: Item ,
2904+ prefix : & str ,
2905+ cx : & Context < ' _ > ,
2906+ ) {
2907+ for attr in & it. attrs . other_attrs {
2908+ render_code_attribute (
2909+ prefix,
2910+ match attr {
2911+ hir:: Attribute :: Parsed ( AttributeKind :: LinkSection { name, .. } ) => {
2912+ Cow :: Owned ( format ! ( "#[unsafe(link_section = \" {}\" )]" , Escape ( name. as_str( ) ) ) )
2913+ }
2914+ hir:: Attribute :: Parsed ( AttributeKind :: NoMangle ( ..) ) => {
2915+ Cow :: Borrowed ( "#[unsafe(no_mangle)]" )
2916+ }
2917+ hir:: Attribute :: Parsed ( AttributeKind :: ExportName { name, .. } ) => {
2918+ Cow :: Owned ( format ! ( "#[unsafe(export_name = \" {}\" )]" , Escape ( name. as_str( ) ) ) )
2919+ }
2920+ hir:: Attribute :: Parsed ( AttributeKind :: NonExhaustive ( ..) ) => {
2921+ Cow :: Borrowed ( "#[non_exhaustive]" )
2922+ }
2923+ _ => continue ,
2924+ }
2925+ . as_ref ( ) ,
2926+ w,
2927+ ) ;
2928+ }
2929+
2930+ if let Some ( def_id) = it. def_id ( )
2931+ && let Some ( repr) = repr_attribute ( cx. tcx ( ) , cx. cache ( ) , def_id)
2932+ {
2933+ render_code_attribute ( prefix, & repr, w) ;
2934+ }
2935+ }
2936+
2937+ fn render_repr_attribute_in_code ( w : & mut impl fmt:: Write , cx : & Context < ' _ > , def_id : DefId ) {
2938+ if let Some ( repr) = repr_attribute ( cx. tcx ( ) , cx. cache ( ) , def_id) {
2939+ render_code_attribute ( "" , & repr, w) ;
2940+ }
2941+ }
2942+
2943+ fn render_code_attribute ( prefix : & str , attr : & str , w : & mut impl fmt:: Write ) {
2944+ write ! ( w, "<div class=\" code-attribute\" >{prefix}{attr}</div>" ) . unwrap ( ) ;
2945+ }
2946+
2947+ fn repr_attribute < ' tcx > (
2948+ tcx : TyCtxt < ' tcx > ,
2949+ cache : & Cache ,
2950+ def_id : DefId ,
2951+ ) -> Option < Cow < ' static , str > > {
2952+ // Read more about private vs. public `#[repr]` here:
2953+ // <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
2954+
2955+ let adt = match tcx. def_kind ( def_id) {
2956+ DefKind :: Struct | DefKind :: Enum | DefKind :: Union => tcx. adt_def ( def_id) ,
2957+ _ => return None ,
2958+ } ;
2959+ let repr = adt. repr ( ) ;
2960+
2961+ let is_visible = |def_id| cache. document_hidden || !tcx. is_doc_hidden ( def_id) ;
2962+ let is_public_field = |field : & ty:: FieldDef | {
2963+ ( cache. document_private || field. vis . is_public ( ) ) && is_visible ( field. did )
2964+ } ;
2965+
2966+ if repr. transparent ( ) {
2967+ // The transparent repr is public iff the non-1-ZST field is public and visible or
2968+ // – in case all fields are 1-ZST fields — at least one field is public and visible.
2969+ let is_public = ' is_public: {
2970+ // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
2971+ let var = adt. variant ( rustc_abi:: FIRST_VARIANT ) ; // the first and only variant
2972+
2973+ if !is_visible ( var. def_id ) {
2974+ break ' is_public false ;
2975+ }
2976+
2977+ // Side note: There can only ever be one or zero non-1-ZST fields.
2978+ let non_1zst_field = var. fields . iter ( ) . find ( |field| {
2979+ let ty = ty:: TypingEnv :: post_analysis ( tcx, field. did )
2980+ . as_query_input ( tcx. type_of ( field. did ) . instantiate_identity ( ) ) ;
2981+ tcx. layout_of ( ty) . is_ok_and ( |layout| !layout. is_1zst ( ) )
2982+ } ) ;
2983+
2984+ match non_1zst_field {
2985+ Some ( field) => is_public_field ( field) ,
2986+ None => var. fields . is_empty ( ) || var. fields . iter ( ) . any ( is_public_field) ,
2987+ }
2988+ } ;
2989+
2990+ // Since the transparent repr can't have any other reprs or
2991+ // repr modifiers beside it, we can safely return early here.
2992+ return is_public. then ( || "#[repr(transparent)]" . into ( ) ) ;
2993+ }
2994+
2995+ // Fast path which avoids looking through the variants and fields in
2996+ // the common case of no `#[repr]` or in the case of `#[repr(Rust)]`.
2997+ // FIXME: This check is not very robust / forward compatible!
2998+ if !repr. c ( )
2999+ && !repr. simd ( )
3000+ && repr. int . is_none ( )
3001+ && repr. pack . is_none ( )
3002+ && repr. align . is_none ( )
3003+ {
3004+ return None ;
3005+ }
3006+
3007+ // The repr is public iff all components are public and visible.
3008+ let is_public = adt
3009+ . variants ( )
3010+ . iter ( )
3011+ . all ( |variant| is_visible ( variant. def_id ) && variant. fields . iter ( ) . all ( is_public_field) ) ;
3012+ if !is_public {
3013+ return None ;
3014+ }
3015+
3016+ let mut result = Vec :: < Cow < ' _ , _ > > :: new ( ) ;
3017+
3018+ if repr. c ( ) {
3019+ result. push ( "C" . into ( ) ) ;
3020+ }
3021+ if repr. simd ( ) {
3022+ result. push ( "simd" . into ( ) ) ;
3023+ }
3024+ if let Some ( int) = repr. int {
3025+ let prefix = if int. is_signed ( ) { 'i' } else { 'u' } ;
3026+ let int = match int {
3027+ rustc_abi:: IntegerType :: Pointer ( _) => format ! ( "{prefix}size" ) ,
3028+ rustc_abi:: IntegerType :: Fixed ( int, _) => {
3029+ format ! ( "{prefix}{}" , int. size( ) . bytes( ) * 8 )
3030+ }
3031+ } ;
3032+ result. push ( int. into ( ) ) ;
3033+ }
3034+
3035+ // Render modifiers last.
3036+ if let Some ( pack) = repr. pack {
3037+ result. push ( format ! ( "packed({})" , pack. bytes( ) ) . into ( ) ) ;
3038+ }
3039+ if let Some ( align) = repr. align {
3040+ result. push ( format ! ( "align({})" , align. bytes( ) ) . into ( ) ) ;
3041+ }
3042+
3043+ ( !result. is_empty ( ) ) . then ( || format ! ( "#[repr({})]" , result. join( ", " ) ) . into ( ) )
3044+ }
0 commit comments