@@ -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,38 +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_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
-
1345
1315
#[ derive( Copy , Clone ) ]
1346
1316
enum AssocItemLink < ' a > {
1347
1317
Anchor ( Option < & ' a str > ) ,
@@ -2927,3 +2897,148 @@ fn render_call_locations<W: fmt::Write>(
2927
2897
2928
2898
w. write_str ( "</div>" )
2929
2899
}
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