@@ -9,10 +9,9 @@ use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
99use rustc_data_structures:: fx:: FxHashMap ;
1010use rustc_errors:: { Applicability , Diagnostic } ;
1111use rustc_feature:: GateIssue ;
12- use rustc_hir as hir;
1312use rustc_hir:: def:: DefKind ;
1413use rustc_hir:: def_id:: { DefId , LocalDefId } ;
15- use rustc_hir:: { self , HirId } ;
14+ use rustc_hir:: { self as hir , HirId } ;
1615use rustc_middle:: ty:: print:: with_no_trimmed_paths;
1716use rustc_session:: lint:: builtin:: { DEPRECATED , DEPRECATED_IN_FUTURE , SOFT_UNSTABLE } ;
1817use rustc_session:: lint:: { BuiltinLintDiagnostics , Level , Lint , LintBuffer } ;
@@ -306,6 +305,14 @@ fn suggestion_for_allocator_api(
306305 None
307306}
308307
308+ /// An override option for eval_stability.
309+ pub enum AllowUnstable {
310+ /// Don't emit an unstable error for the item
311+ Yes ,
312+ /// Handle the item normally
313+ No ,
314+ }
315+
309316impl < ' tcx > TyCtxt < ' tcx > {
310317 /// Evaluates the stability of an item.
311318 ///
@@ -322,6 +329,28 @@ impl<'tcx> TyCtxt<'tcx> {
322329 id : Option < HirId > ,
323330 span : Span ,
324331 method_span : Option < Span > ,
332+ ) -> EvalResult {
333+ self . eval_stability_allow_unstable ( def_id, id, span, method_span, AllowUnstable :: No )
334+ }
335+
336+ /// Evaluates the stability of an item.
337+ ///
338+ /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
339+ /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
340+ /// unstable feature otherwise.
341+ ///
342+ /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
343+ /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
344+ /// `id`.
345+ ///
346+ /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
347+ pub fn eval_stability_allow_unstable (
348+ self ,
349+ def_id : DefId ,
350+ id : Option < HirId > ,
351+ span : Span ,
352+ method_span : Option < Span > ,
353+ allow_unstable : AllowUnstable ,
325354 ) -> EvalResult {
326355 // Deprecated attributes apply in-crate and cross-crate.
327356 if let Some ( id) = id {
@@ -419,6 +448,10 @@ impl<'tcx> TyCtxt<'tcx> {
419448 }
420449 }
421450
451+ if matches ! ( allow_unstable, AllowUnstable :: Yes ) {
452+ return EvalResult :: Allow ;
453+ }
454+
422455 let suggestion = suggestion_for_allocator_api ( self , def_id, span, feature) ;
423456 EvalResult :: Deny { feature, reason, issue, suggestion, is_soft }
424457 }
@@ -445,11 +478,38 @@ impl<'tcx> TyCtxt<'tcx> {
445478 span : Span ,
446479 method_span : Option < Span > ,
447480 ) {
448- self . check_optional_stability ( def_id, id, span, method_span, |span, def_id| {
449- // The API could be uncallable for other reasons, for example when a private module
450- // was referenced.
451- self . sess . delay_span_bug ( span, & format ! ( "encountered unmarked API: {:?}" , def_id) ) ;
452- } )
481+ self . check_stability_allow_unstable ( def_id, id, span, method_span, AllowUnstable :: No )
482+ }
483+
484+ /// Checks if an item is stable or error out.
485+ ///
486+ /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
487+ /// exist, emits an error.
488+ ///
489+ /// This function will also check if the item is deprecated.
490+ /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
491+ ///
492+ /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
493+ pub fn check_stability_allow_unstable (
494+ self ,
495+ def_id : DefId ,
496+ id : Option < HirId > ,
497+ span : Span ,
498+ method_span : Option < Span > ,
499+ allow_unstable : AllowUnstable ,
500+ ) {
501+ self . check_optional_stability (
502+ def_id,
503+ id,
504+ span,
505+ method_span,
506+ allow_unstable,
507+ |span, def_id| {
508+ // The API could be uncallable for other reasons, for example when a private module
509+ // was referenced.
510+ self . sess . delay_span_bug ( span, & format ! ( "encountered unmarked API: {:?}" , def_id) ) ;
511+ } ,
512+ )
453513 }
454514
455515 /// Like `check_stability`, except that we permit items to have custom behaviour for
@@ -462,14 +522,15 @@ impl<'tcx> TyCtxt<'tcx> {
462522 id : Option < HirId > ,
463523 span : Span ,
464524 method_span : Option < Span > ,
525+ allow_unstable : AllowUnstable ,
465526 unmarked : impl FnOnce ( Span , DefId ) ,
466527 ) {
467528 let soft_handler = |lint, span, msg : & _ | {
468529 self . struct_span_lint_hir ( lint, id. unwrap_or ( hir:: CRATE_HIR_ID ) , span, |lint| {
469530 lint. build ( msg) . emit ( ) ;
470531 } )
471532 } ;
472- match self . eval_stability ( def_id, id, span, method_span) {
533+ match self . eval_stability_allow_unstable ( def_id, id, span, method_span, allow_unstable ) {
473534 EvalResult :: Allow => { }
474535 EvalResult :: Deny { feature, reason, issue, suggestion, is_soft } => report_unstable (
475536 self . sess ,
0 commit comments