@@ -51,7 +51,8 @@ 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 } ;
5556use rustc_hir:: def_id:: { DefId , DefIdSet } ;
5657use rustc_hir:: { ConstStability , Mutability , RustcVersion , StabilityLevel , StableSince } ;
5758use rustc_middle:: ty:: print:: PrintTraitRefExt ;
@@ -1310,43 +1311,6 @@ fn render_assoc_item(
13101311 } )
13111312}
13121313
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_attributes_in_code (
1340- w : & mut impl fmt:: Write ,
1341- cx : & Context < ' _ > ,
1342- def_id : DefId ,
1343- item_type : ItemType ,
1344- ) {
1345- if let Some ( repr) = clean:: repr_attributes ( cx. tcx ( ) , cx. cache ( ) , def_id, item_type) {
1346- render_code_attribute ( "" , CodeAttribute ( repr) , w) ;
1347- }
1348- }
1349-
13501314#[ derive( Copy , Clone ) ]
13511315enum AssocItemLink < ' a > {
13521316 Anchor ( Option < & ' a str > ) ,
@@ -2959,3 +2923,144 @@ fn render_call_locations<W: fmt::Write>(
29592923
29602924 w. write_str ( "</div>" )
29612925}
2926+
2927+ struct CodeAttribute ( String ) ;
2928+
2929+ fn render_code_attribute ( prefix : & str , code_attr : CodeAttribute , w : & mut impl fmt:: Write ) {
2930+ write ! (
2931+ w,
2932+ "<div class=\" code-attribute\" >{prefix}{attr}</div>" ,
2933+ prefix = prefix,
2934+ attr = code_attr. 0
2935+ )
2936+ . unwrap ( ) ;
2937+ }
2938+
2939+ // When an attribute is rendered inside a <code> tag, it is formatted using
2940+ // a div to produce a newline after it.
2941+ fn render_attributes_in_code (
2942+ w : & mut impl fmt:: Write ,
2943+ item : & clean:: Item ,
2944+ prefix : & str ,
2945+ cx : & Context < ' _ > ,
2946+ ) {
2947+ for attr in attributes ( item, cx. tcx ( ) , cx. cache ( ) ) {
2948+ render_code_attribute ( prefix, CodeAttribute ( attr) , w) ;
2949+ }
2950+ }
2951+
2952+ /// used for type aliases to only render their `repr` attribute.
2953+ fn render_repr_attributes_in_code (
2954+ w : & mut impl fmt:: Write ,
2955+ cx : & Context < ' _ > ,
2956+ def_id : DefId ,
2957+ item_type : ItemType ,
2958+ ) {
2959+ if let Some ( repr) = repr_attributes ( cx. tcx ( ) , cx. cache ( ) , def_id, item_type) {
2960+ render_code_attribute ( "" , CodeAttribute ( repr) , w) ;
2961+ }
2962+ }
2963+
2964+ /// Get a list of attributes excluding `#[repr]` to display.
2965+ fn attributes_without_repr ( item : & clean:: Item ) -> Vec < String > {
2966+ item. attrs
2967+ . other_attrs
2968+ . iter ( )
2969+ . filter_map ( |attr| match attr {
2970+ hir:: Attribute :: Parsed ( AttributeKind :: LinkSection { name, .. } ) => {
2971+ Some ( format ! ( "#[unsafe(link_section = \" {name}\" )]" ) )
2972+ }
2973+ hir:: Attribute :: Parsed ( AttributeKind :: NoMangle ( ..) ) => {
2974+ Some ( "#[unsafe(no_mangle)]" . to_string ( ) )
2975+ }
2976+ hir:: Attribute :: Parsed ( AttributeKind :: ExportName { name, .. } ) => {
2977+ Some ( format ! ( "#[unsafe(export_name = \" {name}\" )]" ) )
2978+ }
2979+ hir:: Attribute :: Parsed ( AttributeKind :: NonExhaustive ( ..) ) => {
2980+ Some ( "#[non_exhaustive]" . to_string ( ) )
2981+ }
2982+ _ => None ,
2983+ } )
2984+ . collect ( )
2985+ }
2986+
2987+ /// Get a list of attributes to display on this item.
2988+ fn attributes ( item : & clean:: Item , tcx : TyCtxt < ' _ > , cache : & Cache ) -> Vec < String > {
2989+ let mut attrs = attributes_without_repr ( item) ;
2990+
2991+ if let Some ( repr_attr) = repr ( item, tcx, cache) {
2992+ attrs. push ( repr_attr) ;
2993+ }
2994+ attrs
2995+ }
2996+
2997+ /// Returns a stringified `#[repr(...)]` attribute.
2998+ fn repr ( item : & clean:: Item , tcx : TyCtxt < ' _ > , cache : & Cache ) -> Option < String > {
2999+ repr_attributes ( tcx, cache, item. def_id ( ) ?, item. type_ ( ) )
3000+ }
3001+
3002+ /// Return a string representing the `#[repr]` attribute if present.
3003+ pub ( crate ) fn repr_attributes (
3004+ tcx : TyCtxt < ' _ > ,
3005+ cache : & Cache ,
3006+ def_id : DefId ,
3007+ item_type : ItemType ,
3008+ ) -> Option < String > {
3009+ use rustc_abi:: IntegerType ;
3010+
3011+ if !matches ! ( item_type, ItemType :: Struct | ItemType :: Enum | ItemType :: Union ) {
3012+ return None ;
3013+ }
3014+ let adt = tcx. adt_def ( def_id) ;
3015+ let repr = adt. repr ( ) ;
3016+ let mut out = Vec :: new ( ) ;
3017+ if repr. c ( ) {
3018+ out. push ( "C" ) ;
3019+ }
3020+ if repr. transparent ( ) {
3021+ // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
3022+ // field is public in case all fields are 1-ZST fields.
3023+ let render_transparent = cache. document_private
3024+ || adt
3025+ . all_fields ( )
3026+ . find ( |field| {
3027+ let ty = field. ty ( tcx, ty:: GenericArgs :: identity_for_item ( tcx, field. did ) ) ;
3028+ tcx. layout_of ( ty:: TypingEnv :: post_analysis ( tcx, field. did ) . as_query_input ( ty) )
3029+ . is_ok_and ( |layout| !layout. is_1zst ( ) )
3030+ } )
3031+ . map_or_else (
3032+ || adt. all_fields ( ) . any ( |field| field. vis . is_public ( ) ) ,
3033+ |field| field. vis . is_public ( ) ,
3034+ ) ;
3035+
3036+ if render_transparent {
3037+ out. push ( "transparent" ) ;
3038+ }
3039+ }
3040+ if repr. simd ( ) {
3041+ out. push ( "simd" ) ;
3042+ }
3043+ let pack_s;
3044+ if let Some ( pack) = repr. pack {
3045+ pack_s = format ! ( "packed({})" , pack. bytes( ) ) ;
3046+ out. push ( & pack_s) ;
3047+ }
3048+ let align_s;
3049+ if let Some ( align) = repr. align {
3050+ align_s = format ! ( "align({})" , align. bytes( ) ) ;
3051+ out. push ( & align_s) ;
3052+ }
3053+ let int_s;
3054+ if let Some ( int) = repr. int {
3055+ int_s = match int {
3056+ IntegerType :: Pointer ( is_signed) => {
3057+ format ! ( "{}size" , if is_signed { 'i' } else { 'u' } )
3058+ }
3059+ IntegerType :: Fixed ( size, is_signed) => {
3060+ format ! ( "{}{}" , if is_signed { 'i' } else { 'u' } , size. size( ) . bytes( ) * 8 )
3061+ }
3062+ } ;
3063+ out. push ( & int_s) ;
3064+ }
3065+ if !out. is_empty ( ) { Some ( format ! ( "#[repr({})]" , out. join( ", " ) ) ) } else { None }
3066+ }
0 commit comments