@@ -8,9 +8,9 @@ use rustc_data_structures::fx::FxHashSet;
88use rustc_data_structures:: thin_vec:: ThinVec ;
99use rustc_hir as hir;
1010use rustc_hir:: attrs:: { self , DeprecatedSince , DocAttribute , DocInline , HideOrShow } ;
11- use rustc_hir:: def:: CtorKind ;
11+ use rustc_hir:: def:: { CtorKind , DefKind } ;
1212use rustc_hir:: def_id:: DefId ;
13- use rustc_hir:: { HeaderSafety , Safety } ;
13+ use rustc_hir:: { HeaderSafety , Safety , find_attr } ;
1414use rustc_metadata:: rendered_const;
1515use rustc_middle:: ty:: TyCtxt ;
1616use rustc_middle:: { bug, ty} ;
@@ -92,6 +92,9 @@ impl JsonRenderer<'_> {
9292 item. item_id . as_def_id ( )
9393 } ;
9494 let stability = stability_def_id. and_then ( |def_id| self . tcx . lookup_stability ( def_id) ) ;
95+ let const_stability = item. item_id . as_def_id ( ) . and_then ( |def_id| {
96+ const_stability_for_def_id ( self . tcx , def_id) . map ( |s| Box :: new ( s. into_json ( self ) ) )
97+ } ) ;
9598
9699 Some ( Item {
97100 id,
@@ -100,6 +103,7 @@ impl JsonRenderer<'_> {
100103 span : span. and_then ( |span| span. into_json ( self ) ) ,
101104 visibility : visibility. into_json ( self ) ,
102105 stability : stability. map ( |s| Box :: new ( s. into_json ( self ) ) ) ,
106+ const_stability,
103107 docs,
104108 attrs,
105109 deprecation : deprecation. into_json ( self ) ,
@@ -246,6 +250,24 @@ impl FromClean<hir::Stability> for Stability {
246250 }
247251}
248252
253+ impl FromClean < hir:: ConstStability > for Stability {
254+ fn from_clean ( stab : & hir:: ConstStability , _renderer : & JsonRenderer < ' _ > ) -> Self {
255+ let feature = stab. feature . to_string ( ) ;
256+ let level = match stab. level {
257+ hir:: StabilityLevel :: Stable { since, .. } => StabilityLevel :: Stable {
258+ since : match since {
259+ hir:: StableSince :: Version ( since) => Some ( since. to_string ( ) ) ,
260+ hir:: StableSince :: Current => Some ( hir:: RustcVersion :: CURRENT . to_string ( ) ) ,
261+ // Match rustdoc HTML: malformed stable-since values are omitted.
262+ hir:: StableSince :: Err ( _) => None ,
263+ } ,
264+ } ,
265+ hir:: StabilityLevel :: Unstable { .. } => StabilityLevel :: Unstable ,
266+ } ;
267+ Stability { feature, level }
268+ }
269+ }
270+
249271impl FromClean < clean:: GenericArgs > for Option < Box < GenericArgs > > {
250272 fn from_clean ( generic_args : & clean:: GenericArgs , renderer : & JsonRenderer < ' _ > ) -> Self {
251273 use clean:: GenericArgs :: * ;
@@ -948,6 +970,55 @@ impl FromClean<ItemType> for ItemKind {
948970 }
949971}
950972
973+ fn const_stability_for_def_id ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < hir:: ConstStability > {
974+ if !tcx. is_conditionally_const ( def_id) {
975+ // The item cannot be conditionally-const. No const stability here.
976+ //
977+ // This includes associated consts, which are an interesting exception
978+ // to the general rule that items inside `const impl` and `const trait` carry
979+ // the const-stability of that block. Associated consts are already const, always.
980+ return None ;
981+ }
982+
983+ let const_stability = tcx. lookup_const_stability ( def_id) ?;
984+ if find_attr ! ( tcx, def_id, RustcConstStability { .. } ) {
985+ // Direct const-stability attribute on the item itself. Return it directly.
986+ return Some ( const_stability) ;
987+ }
988+
989+ if const_stability. is_const_stable ( ) {
990+ // Items that are const-stable without an explicit attribute on their own item
991+ // must be associated items inside `const trait` or `const impl`.
992+ // We don't want to duplicate their parent item's const-stability attribute.
993+ return None ;
994+ }
995+
996+ // We're dealing with an item that is const-unstable,
997+ // but doesn't have an explicit const-stability attribute on it.
998+ //
999+ // Today, this means one of two cases:
1000+ // - The item is enclosed within a `#[rustc_const_unstable]` block,
1001+ // like a `const trait` or `const impl`, in which case our query propagated the parent's
1002+ // const-instability info. This const-instability is desirable to place into JSON
1003+ // because *only some* associated items inside such a block are const-unstable.
1004+ // Associated consts are the exception, and were handled earlier.
1005+ // - The item is `#[unstable]` which implies it's const-unstable under the same feature,
1006+ // in which case we don't want to duplicate the existing stability attribute
1007+ // which would already appear in an adjacent field in the JSON anyway.
1008+ if let Some ( parent_def_id) = tcx. opt_parent ( def_id)
1009+ && matches ! ( tcx. def_kind( parent_def_id) , DefKind :: Trait | DefKind :: Impl { .. } )
1010+ && tcx. lookup_const_stability ( parent_def_id) == Some ( const_stability)
1011+ {
1012+ Some ( const_stability)
1013+ } else {
1014+ std:: debug_assert_matches!(
1015+ tcx. lookup_stability( def_id) . map( |s| s. level) ,
1016+ Some ( hir:: StabilityLevel :: Unstable { .. } )
1017+ ) ;
1018+ None
1019+ }
1020+ }
1021+
9511022/// Maybe convert a attribute from hir to json.
9521023///
9531024/// Returns `None` if the attribute shouldn't be in the output.
@@ -966,6 +1037,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>)
9661037 vec ! [ match kind {
9671038 AK :: Deprecated { .. } => return Vec :: new( ) , // Handled separately into Item::deprecation.
9681039 AK :: Stability { .. } => return Vec :: new( ) , // Handled separately into Item::stability
1040+ AK :: RustcConstStability { .. } => return Vec :: new( ) , // Handled separately into Item::const_stability.
9691041
9701042 AK :: DocComment { .. } => unreachable!( "doc comments stripped out earlier" ) ,
9711043
0 commit comments