@@ -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,43 +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_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-
13501315#[ derive( Copy , Clone ) ]
13511316enum AssocItemLink < ' a > {
13521317 Anchor ( Option < & ' a str > ) ,
@@ -2959,3 +2924,142 @@ fn render_call_locations<W: fmt::Write>(
29592924
29602925 w. write_str ( "</div>" )
29612926}
2927+
2928+ fn render_attributes_in_code (
2929+ w : & mut impl fmt:: Write ,
2930+ item : & clean:: Item ,
2931+ prefix : & str ,
2932+ cx : & Context < ' _ > ,
2933+ ) {
2934+ for attr in & item. attrs . other_attrs {
2935+ let hir:: Attribute :: Parsed ( kind) = attr else { continue } ;
2936+ let attr = match kind {
2937+ AttributeKind :: LinkSection { name, .. } => {
2938+ Cow :: Owned ( format ! ( "#[unsafe(link_section = {})]" , Escape ( & format!( "{name:?}" ) ) ) )
2939+ }
2940+ AttributeKind :: NoMangle ( ..) => Cow :: Borrowed ( "#[unsafe(no_mangle)]" ) ,
2941+ AttributeKind :: ExportName { name, .. } => {
2942+ Cow :: Owned ( format ! ( "#[unsafe(export_name = {})]" , Escape ( & format!( "{name:?}" ) ) ) )
2943+ }
2944+ AttributeKind :: NonExhaustive ( ..) => Cow :: Borrowed ( "#[non_exhaustive]" ) ,
2945+ _ => continue ,
2946+ } ;
2947+ render_code_attribute ( prefix, attr. as_ref ( ) , w) ;
2948+ }
2949+
2950+ if let Some ( def_id) = item. def_id ( )
2951+ && let Some ( repr) = repr_attribute ( cx. tcx ( ) , cx. cache ( ) , def_id)
2952+ {
2953+ render_code_attribute ( prefix, & repr, w) ;
2954+ }
2955+ }
2956+
2957+ fn render_repr_attribute_in_code ( w : & mut impl fmt:: Write , cx : & Context < ' _ > , def_id : DefId ) {
2958+ if let Some ( repr) = repr_attribute ( cx. tcx ( ) , cx. cache ( ) , def_id) {
2959+ render_code_attribute ( "" , & repr, w) ;
2960+ }
2961+ }
2962+
2963+ fn render_code_attribute ( prefix : & str , attr : & str , w : & mut impl fmt:: Write ) {
2964+ write ! ( w, "<div class=\" code-attribute\" >{prefix}{attr}</div>" ) . unwrap ( ) ;
2965+ }
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>.
2971+ fn repr_attribute < ' tcx > (
2972+ tcx : TyCtxt < ' tcx > ,
2973+ cache : & Cache ,
2974+ def_id : DefId ,
2975+ ) -> Option < Cow < ' static , str > > {
2976+ let adt = match tcx. def_kind ( def_id) {
2977+ DefKind :: Struct | DefKind :: Enum | DefKind :: Union => tcx. adt_def ( def_id) ,
2978+ _ => return None ,
2979+ } ;
2980+ let repr = adt. repr ( ) ;
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+
2987+ if repr. transparent ( ) {
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+ } ;
3010+
3011+ // Since the transparent repr can't have any other reprs or
3012+ // repr modifiers beside it, we can safely return early here.
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 ;
3035+ }
3036+
3037+ let mut result = Vec :: < Cow < ' _ , _ > > :: new ( ) ;
3038+
3039+ if repr. c ( ) {
3040+ result. push ( "C" . into ( ) ) ;
3041+ }
3042+ if repr. simd ( ) {
3043+ result. push ( "simd" . into ( ) ) ;
3044+ }
3045+ if let Some ( int) = repr. int {
3046+ let prefix = if int. is_signed ( ) { 'i' } else { 'u' } ;
3047+ let int = match int {
3048+ rustc_abi:: IntegerType :: Pointer ( _) => format ! ( "{prefix}size" ) ,
3049+ rustc_abi:: IntegerType :: Fixed ( int, _) => {
3050+ format ! ( "{prefix}{}" , int. size( ) . bytes( ) * 8 )
3051+ }
3052+ } ;
3053+ result. push ( int. into ( ) ) ;
3054+ }
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+
3064+ ( !result. is_empty ( ) ) . then ( || format ! ( "#[repr({})]" , result. join( ", " ) ) . into ( ) )
3065+ }
0 commit comments