@@ -9,10 +9,9 @@ use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
9
9
use rustc_data_structures:: fx:: FxHashMap ;
10
10
use rustc_errors:: { Applicability , Diagnostic } ;
11
11
use rustc_feature:: GateIssue ;
12
- use rustc_hir as hir;
13
12
use rustc_hir:: def:: DefKind ;
14
13
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
15
- use rustc_hir:: { self , HirId } ;
14
+ use rustc_hir:: { self as hir , HirId } ;
16
15
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
17
16
use rustc_session:: lint:: builtin:: { DEPRECATED , DEPRECATED_IN_FUTURE , SOFT_UNSTABLE } ;
18
17
use rustc_session:: lint:: { BuiltinLintDiagnostics , Level , Lint , LintBuffer } ;
@@ -306,6 +305,14 @@ fn suggestion_for_allocator_api(
306
305
None
307
306
}
308
307
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
+
309
316
impl < ' tcx > TyCtxt < ' tcx > {
310
317
/// Evaluates the stability of an item.
311
318
///
@@ -322,6 +329,28 @@ impl<'tcx> TyCtxt<'tcx> {
322
329
id : Option < HirId > ,
323
330
span : Span ,
324
331
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 ,
325
354
) -> EvalResult {
326
355
// Deprecated attributes apply in-crate and cross-crate.
327
356
if let Some ( id) = id {
@@ -419,6 +448,10 @@ impl<'tcx> TyCtxt<'tcx> {
419
448
}
420
449
}
421
450
451
+ if matches ! ( allow_unstable, AllowUnstable :: Yes ) {
452
+ return EvalResult :: Allow ;
453
+ }
454
+
422
455
let suggestion = suggestion_for_allocator_api ( self , def_id, span, feature) ;
423
456
EvalResult :: Deny { feature, reason, issue, suggestion, is_soft }
424
457
}
@@ -445,11 +478,38 @@ impl<'tcx> TyCtxt<'tcx> {
445
478
span : Span ,
446
479
method_span : Option < Span > ,
447
480
) {
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
+ )
453
513
}
454
514
455
515
/// Like `check_stability`, except that we permit items to have custom behaviour for
@@ -462,14 +522,15 @@ impl<'tcx> TyCtxt<'tcx> {
462
522
id : Option < HirId > ,
463
523
span : Span ,
464
524
method_span : Option < Span > ,
525
+ allow_unstable : AllowUnstable ,
465
526
unmarked : impl FnOnce ( Span , DefId ) ,
466
527
) {
467
528
let soft_handler = |lint, span, msg : & _ | {
468
529
self . struct_span_lint_hir ( lint, id. unwrap_or ( hir:: CRATE_HIR_ID ) , span, |lint| {
469
530
lint. build ( msg) . emit ( ) ;
470
531
} )
471
532
} ;
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 ) {
473
534
EvalResult :: Allow => { }
474
535
EvalResult :: Deny { feature, reason, issue, suggestion, is_soft } => report_unstable (
475
536
self . sess ,
0 commit comments