@@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
55
66use crate :: ty:: { self , DefIdTree , TyCtxt } ;
77use rustc_ast:: NodeId ;
8- use rustc_attr:: { self as attr, ConstStability , Deprecation , Stability } ;
8+ use rustc_attr:: { self as attr, ConstStability , DefaultBodyStability , Deprecation , Stability } ;
99use rustc_data_structures:: fx:: FxHashMap ;
1010use rustc_errors:: { Applicability , Diagnostic } ;
1111use rustc_feature:: GateIssue ;
@@ -61,6 +61,7 @@ pub struct Index {
6161 /// are filled by the annotator.
6262 pub stab_map : FxHashMap < LocalDefId , Stability > ,
6363 pub const_stab_map : FxHashMap < LocalDefId , ConstStability > ,
64+ pub default_body_stab_map : FxHashMap < LocalDefId , DefaultBodyStability > ,
6465 pub depr_map : FxHashMap < LocalDefId , DeprecationEntry > ,
6566 /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
6667 /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
@@ -86,6 +87,10 @@ impl Index {
8687 self . const_stab_map . get ( & def_id) . copied ( )
8788 }
8889
90+ pub fn local_default_body_stability ( & self , def_id : LocalDefId ) -> Option < DefaultBodyStability > {
91+ self . default_body_stab_map . get ( & def_id) . copied ( )
92+ }
93+
8994 pub fn local_deprecation_entry ( & self , def_id : LocalDefId ) -> Option < DeprecationEntry > {
9095 self . depr_map . get ( & def_id) . cloned ( )
9196 }
@@ -416,19 +421,19 @@ impl<'tcx> TyCtxt<'tcx> {
416421 return EvalResult :: Allow ;
417422 }
418423
424+ // Only the cross-crate scenario matters when checking unstable APIs
425+ let cross_crate = !def_id. is_local ( ) ;
426+ if !cross_crate {
427+ return EvalResult :: Allow ;
428+ }
429+
419430 let stability = self . lookup_stability ( def_id) ;
420431 debug ! (
421432 "stability: \
422433 inspecting def_id={:?} span={:?} of stability={:?}",
423434 def_id, span, stability
424435 ) ;
425436
426- // Only the cross-crate scenario matters when checking unstable APIs
427- let cross_crate = !def_id. is_local ( ) ;
428- if !cross_crate {
429- return EvalResult :: Allow ;
430- }
431-
432437 // Issue #38412: private items lack stability markers.
433438 if skip_stability_check_due_to_privacy ( self , def_id) {
434439 return EvalResult :: Allow ;
@@ -492,6 +497,62 @@ impl<'tcx> TyCtxt<'tcx> {
492497 }
493498 }
494499
500+ /// Evaluates the default-impl stability of an item.
501+ ///
502+ /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
503+ /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
504+ /// unstable feature otherwise.
505+ pub fn eval_default_body_stability ( self , def_id : DefId , span : Span ) -> EvalResult {
506+ let is_staged_api = self . lookup_stability ( def_id. krate . as_def_id ( ) ) . is_some ( ) ;
507+ if !is_staged_api {
508+ return EvalResult :: Allow ;
509+ }
510+
511+ // Only the cross-crate scenario matters when checking unstable APIs
512+ let cross_crate = !def_id. is_local ( ) ;
513+ if !cross_crate {
514+ return EvalResult :: Allow ;
515+ }
516+
517+ let stability = self . lookup_default_body_stability ( def_id) ;
518+ debug ! (
519+ "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
520+ ) ;
521+
522+ // Issue #38412: private items lack stability markers.
523+ if skip_stability_check_due_to_privacy ( self , def_id) {
524+ return EvalResult :: Allow ;
525+ }
526+
527+ match stability {
528+ Some ( DefaultBodyStability {
529+ level : attr:: Unstable { reason, issue, is_soft, .. } ,
530+ feature,
531+ } ) => {
532+ if span. allows_unstable ( feature) {
533+ debug ! ( "body stability: skipping span={:?} since it is internal" , span) ;
534+ return EvalResult :: Allow ;
535+ }
536+ if self . features ( ) . active ( feature) {
537+ return EvalResult :: Allow ;
538+ }
539+
540+ EvalResult :: Deny {
541+ feature,
542+ reason : reason. to_opt_reason ( ) ,
543+ issue,
544+ suggestion : None ,
545+ is_soft,
546+ }
547+ }
548+ Some ( _) => {
549+ // Stable APIs are always ok to call
550+ EvalResult :: Allow
551+ }
552+ None => EvalResult :: Unmarked ,
553+ }
554+ }
555+
495556 /// Checks if an item is stable or error out.
496557 ///
497558 /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
0 commit comments