@@ -474,6 +474,22 @@ struct Checker<'a, 'tcx: 'a> {
474474 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
475475}
476476
477+ /// Result of `TyCtxt::eval_stability`.
478+ pub enum EvalResult {
479+ /// We can use the item because it is stable or we provided the
480+ /// corresponding feature gate.
481+ Allow ,
482+ /// We cannot use the item because it is unstable and we did not provide the
483+ /// corresponding feature gate.
484+ Deny {
485+ feature : Symbol ,
486+ reason : Option < Symbol > ,
487+ issue : u32 ,
488+ } ,
489+ /// The item does not have the `#[stable]` or `#[unstable]` marker assigned.
490+ Unmarked ,
491+ }
492+
477493impl < ' a , ' gcx , ' tcx > TyCtxt < ' a , ' gcx , ' tcx > {
478494 // (See issue #38412)
479495 fn skip_stability_check_due_to_privacy ( self , mut def_id : DefId ) -> bool {
@@ -509,14 +525,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
509525 }
510526 }
511527
512- pub fn check_stability ( self , def_id : DefId , id : NodeId , span : Span ) {
528+ /// Evaluates the stability of an item.
529+ ///
530+ /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
531+ /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
532+ /// unstable feature otherwise.
533+ ///
534+ /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
535+ /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
536+ /// `id`.
537+ pub fn eval_stability ( self , def_id : DefId , id : Option < NodeId > , span : Span ) -> EvalResult {
513538 if span. allows_unstable ( ) {
514539 debug ! ( "stability: \
515540 skipping span={:?} since it is internal", span) ;
516- return ;
541+ return EvalResult :: Allow ;
517542 }
518543
519- let lint_deprecated = |def_id : DefId , note : Option < Symbol > | {
544+ let lint_deprecated = |def_id : DefId , id : NodeId , note : Option < Symbol > | {
520545 let path = self . item_path_str ( def_id) ;
521546
522547 let msg = if let Some ( note) = note {
@@ -526,30 +551,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
526551 } ;
527552
528553 self . lint_node ( lint:: builtin:: DEPRECATED , id, span, & msg) ;
554+ if id == ast:: DUMMY_NODE_ID {
555+ span_bug ! ( span, "emitted a deprecated lint with dummy node id: {:?}" , def_id) ;
556+ }
529557 } ;
530558
531559 // Deprecated attributes apply in-crate and cross-crate.
532- if let Some ( depr_entry) = self . lookup_deprecation_entry ( def_id) {
533- let skip = if id == ast:: DUMMY_NODE_ID {
534- true
535- } else {
560+ if let Some ( id) = id {
561+ if let Some ( depr_entry) = self . lookup_deprecation_entry ( def_id) {
536562 let parent_def_id = self . hir . local_def_id ( self . hir . get_parent ( id) ) ;
537- self . lookup_deprecation_entry ( parent_def_id) . map_or ( false , |parent_depr| {
538- parent_depr. same_origin ( & depr_entry)
539- } )
563+ let skip = self . lookup_deprecation_entry ( parent_def_id)
564+ . map_or ( false , |parent_depr| parent_depr. same_origin ( & depr_entry) ) ;
565+ if !skip {
566+ lint_deprecated ( def_id, id, depr_entry. attr . note ) ;
567+ }
540568 } ;
541-
542- if !skip {
543- lint_deprecated ( def_id, depr_entry. attr . note ) ;
544- }
545569 }
546570
547571 let is_staged_api = self . lookup_stability ( DefId {
548572 index : CRATE_DEF_INDEX ,
549573 ..def_id
550574 } ) . is_some ( ) ;
551575 if !is_staged_api {
552- return ;
576+ return EvalResult :: Allow ;
553577 }
554578
555579 let stability = self . lookup_stability ( def_id) ;
@@ -558,26 +582,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
558582
559583 if let Some ( & Stability { rustc_depr : Some ( attr:: RustcDeprecation { reason, .. } ) , ..} )
560584 = stability {
561- if id != ast :: DUMMY_NODE_ID {
562- lint_deprecated ( def_id, Some ( reason) ) ;
585+ if let Some ( id ) = id {
586+ lint_deprecated ( def_id, id , Some ( reason) ) ;
563587 }
564588 }
565589
566590 // Only the cross-crate scenario matters when checking unstable APIs
567591 let cross_crate = !def_id. is_local ( ) ;
568592 if !cross_crate {
569- return
593+ return EvalResult :: Allow ;
570594 }
571595
572596 // Issue 38412: private items lack stability markers.
573597 if self . skip_stability_check_due_to_privacy ( def_id) {
574- return
598+ return EvalResult :: Allow ;
575599 }
576600
577601 match stability {
578- Some ( & Stability { level : attr:: Unstable { ref reason, issue} , ref feature, .. } ) => {
579- if self . stability ( ) . active_features . contains ( feature) {
580- return
602+ Some ( & Stability { level : attr:: Unstable { reason, issue } , feature, .. } ) => {
603+ if self . stability ( ) . active_features . contains ( & feature) {
604+ return EvalResult :: Allow ;
581605 }
582606
583607 // When we're compiling the compiler itself we may pull in
@@ -589,19 +613,41 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
589613 // the `-Z force-unstable-if-unmarked` flag present (we're
590614 // compiling a compiler crate), then let this missing feature
591615 // annotation slide.
592- if * feature == "rustc_private" && issue == 27812 {
616+ if feature == "rustc_private" && issue == 27812 {
593617 if self . sess . opts . debugging_opts . force_unstable_if_unmarked {
594- return
618+ return EvalResult :: Allow ;
595619 }
596620 }
597621
598- let msg = match * reason {
599- Some ( ref r) => format ! ( "use of unstable library feature '{}': {}" ,
600- feature. as_str( ) , & r) ,
622+ EvalResult :: Deny { feature, reason, issue }
623+ }
624+ Some ( _) => {
625+ // Stable APIs are always ok to call and deprecated APIs are
626+ // handled by the lint emitting logic above.
627+ EvalResult :: Allow
628+ }
629+ None => {
630+ EvalResult :: Unmarked
631+ }
632+ }
633+ }
634+
635+ /// Checks if an item is stable or error out.
636+ ///
637+ /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
638+ /// exist, emits an error.
639+ ///
640+ /// Additionally, this function will also check if the item is deprecated. If so, and `id` is
641+ /// not `None`, a deprecated lint attached to `id` will be emitted.
642+ pub fn check_stability ( self , def_id : DefId , id : Option < NodeId > , span : Span ) {
643+ match self . eval_stability ( def_id, id, span) {
644+ EvalResult :: Allow => { }
645+ EvalResult :: Deny { feature, reason, issue } => {
646+ let msg = match reason {
647+ Some ( r) => format ! ( "use of unstable library feature '{}': {}" , feature, r) ,
601648 None => format ! ( "use of unstable library feature '{}'" , & feature)
602649 } ;
603650
604-
605651 let msp: MultiSpan = span. into ( ) ;
606652 let cm = & self . sess . parse_sess . codemap ( ) ;
607653 let span_key = msp. primary_span ( ) . and_then ( |sp : Span |
@@ -624,12 +670,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
624670 GateIssue :: Library ( Some ( issue) ) , & msg) ;
625671 }
626672 }
627- Some ( _) => {
628- // Stable APIs are always ok to call and deprecated APIs are
629- // handled by the lint emitting logic above.
630- }
631- None => {
632- span_bug ! ( span, "encountered unmarked API" ) ;
673+ EvalResult :: Unmarked => {
674+ span_bug ! ( span, "encountered unmarked API: {:?}" , def_id) ;
633675 }
634676 }
635677 }
@@ -655,7 +697,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
655697 None => return ,
656698 } ;
657699 let def_id = DefId { krate : cnum, index : CRATE_DEF_INDEX } ;
658- self . tcx . check_stability ( def_id, item. id , item. span ) ;
700+ self . tcx . check_stability ( def_id, Some ( item. id ) , item. span ) ;
659701 }
660702
661703 // For implementations of traits, check the stability of each item
@@ -668,8 +710,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
668710 let trait_item_def_id = self . tcx . associated_items ( trait_did)
669711 . find ( |item| item. name == impl_item. name ) . map ( |item| item. def_id ) ;
670712 if let Some ( def_id) = trait_item_def_id {
671- // Pass `DUMMY_NODE_ID ` to skip deprecation warnings.
672- self . tcx . check_stability ( def_id, ast :: DUMMY_NODE_ID , impl_item. span ) ;
713+ // Pass `None ` to skip deprecation warnings.
714+ self . tcx . check_stability ( def_id, None , impl_item. span ) ;
673715 }
674716 }
675717 }
@@ -705,7 +747,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
705747 match path. def {
706748 Def :: Local ( ..) | Def :: Upvar ( ..) |
707749 Def :: PrimTy ( ..) | Def :: SelfTy ( ..) | Def :: Err => { }
708- _ => self . tcx . check_stability ( path. def . def_id ( ) , id , path. span )
750+ _ => self . tcx . check_stability ( path. def . def_id ( ) , Some ( id ) , path. span )
709751 }
710752 intravisit:: walk_path ( self , path)
711753 }
0 commit comments