@@ -474,6 +474,22 @@ struct Checker<'a, 'tcx: 'a> {
474
474
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
475
475
}
476
476
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
+
477
493
impl < ' a , ' gcx , ' tcx > TyCtxt < ' a , ' gcx , ' tcx > {
478
494
// (See issue #38412)
479
495
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> {
509
525
}
510
526
}
511
527
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 {
513
538
if span. allows_unstable ( ) {
514
539
debug ! ( "stability: \
515
540
skipping span={:?} since it is internal", span) ;
516
- return ;
541
+ return EvalResult :: Allow ;
517
542
}
518
543
519
- let lint_deprecated = |def_id : DefId , note : Option < Symbol > | {
544
+ let lint_deprecated = |def_id : DefId , id : NodeId , note : Option < Symbol > | {
520
545
let path = self . item_path_str ( def_id) ;
521
546
522
547
let msg = if let Some ( note) = note {
@@ -526,30 +551,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
526
551
} ;
527
552
528
553
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
+ }
529
557
} ;
530
558
531
559
// 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) {
536
562
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
+ }
540
568
} ;
541
-
542
- if !skip {
543
- lint_deprecated ( def_id, depr_entry. attr . note ) ;
544
- }
545
569
}
546
570
547
571
let is_staged_api = self . lookup_stability ( DefId {
548
572
index : CRATE_DEF_INDEX ,
549
573
..def_id
550
574
} ) . is_some ( ) ;
551
575
if !is_staged_api {
552
- return ;
576
+ return EvalResult :: Allow ;
553
577
}
554
578
555
579
let stability = self . lookup_stability ( def_id) ;
@@ -558,26 +582,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
558
582
559
583
if let Some ( & Stability { rustc_depr : Some ( attr:: RustcDeprecation { reason, .. } ) , ..} )
560
584
= 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) ) ;
563
587
}
564
588
}
565
589
566
590
// Only the cross-crate scenario matters when checking unstable APIs
567
591
let cross_crate = !def_id. is_local ( ) ;
568
592
if !cross_crate {
569
- return
593
+ return EvalResult :: Allow ;
570
594
}
571
595
572
596
// Issue 38412: private items lack stability markers.
573
597
if self . skip_stability_check_due_to_privacy ( def_id) {
574
- return
598
+ return EvalResult :: Allow ;
575
599
}
576
600
577
601
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 ;
581
605
}
582
606
583
607
// When we're compiling the compiler itself we may pull in
@@ -589,19 +613,41 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
589
613
// the `-Z force-unstable-if-unmarked` flag present (we're
590
614
// compiling a compiler crate), then let this missing feature
591
615
// annotation slide.
592
- if * feature == "rustc_private" && issue == 27812 {
616
+ if feature == "rustc_private" && issue == 27812 {
593
617
if self . sess . opts . debugging_opts . force_unstable_if_unmarked {
594
- return
618
+ return EvalResult :: Allow ;
595
619
}
596
620
}
597
621
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) ,
601
648
None => format ! ( "use of unstable library feature '{}'" , & feature)
602
649
} ;
603
650
604
-
605
651
let msp: MultiSpan = span. into ( ) ;
606
652
let cm = & self . sess . parse_sess . codemap ( ) ;
607
653
let span_key = msp. primary_span ( ) . and_then ( |sp : Span |
@@ -624,12 +670,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
624
670
GateIssue :: Library ( Some ( issue) ) , & msg) ;
625
671
}
626
672
}
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) ;
633
675
}
634
676
}
635
677
}
@@ -655,7 +697,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
655
697
None => return ,
656
698
} ;
657
699
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 ) ;
659
701
}
660
702
661
703
// For implementations of traits, check the stability of each item
@@ -668,8 +710,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
668
710
let trait_item_def_id = self . tcx . associated_items ( trait_did)
669
711
. find ( |item| item. name == impl_item. name ) . map ( |item| item. def_id ) ;
670
712
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 ) ;
673
715
}
674
716
}
675
717
}
@@ -705,7 +747,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
705
747
match path. def {
706
748
Def :: Local ( ..) | Def :: Upvar ( ..) |
707
749
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 )
709
751
}
710
752
intravisit:: walk_path ( self , path)
711
753
}
0 commit comments