@@ -51,7 +51,9 @@ use askama::Template;
51
51
use itertools:: Either ;
52
52
use rustc_ast:: join_path_syms;
53
53
use 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 ;
55
57
use rustc_hir:: def_id:: { DefId , DefIdSet } ;
56
58
use rustc_hir:: { ConstStability , Mutability , RustcVersion , StabilityLevel , StableSince } ;
57
59
use rustc_middle:: ty:: print:: PrintTraitRefExt ;
@@ -1310,43 +1312,6 @@ fn render_assoc_item(
1310
1312
} )
1311
1313
}
1312
1314
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
-
1350
1315
#[ derive( Copy , Clone ) ]
1351
1316
enum AssocItemLink < ' a > {
1352
1317
Anchor ( Option < & ' a str > ) ,
@@ -2959,3 +2924,142 @@ fn render_call_locations<W: fmt::Write>(
2959
2924
2960
2925
w. write_str ( "</div>" )
2961
2926
}
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