@@ -10,6 +10,7 @@ use rustc_attr_parsing::{
10
10
use rustc_data_structures:: unord:: UnordMap ;
11
11
use rustc_errors:: { Applicability , Diag , EmissionGuarantee } ;
12
12
use rustc_feature:: GateIssue ;
13
+ use rustc_hir:: def:: DefKind ;
13
14
use rustc_hir:: def_id:: { DefId , LocalDefId , LocalDefIdMap } ;
14
15
use rustc_hir:: { self as hir, HirId } ;
15
16
use rustc_macros:: { Decodable , Encodable , HashStable , Subdiagnostic } ;
@@ -18,7 +19,7 @@ use rustc_session::Session;
18
19
use rustc_session:: lint:: builtin:: { DEPRECATED , DEPRECATED_IN_FUTURE , SOFT_UNSTABLE } ;
19
20
use rustc_session:: lint:: { BuiltinLintDiag , DeprecatedSinceKind , Level , Lint , LintBuffer } ;
20
21
use rustc_session:: parse:: feature_err_issue;
21
- use rustc_span:: { Span , Symbol , sym} ;
22
+ use rustc_span:: { ErrorGuaranteed , Span , Symbol , sym} ;
22
23
use tracing:: debug;
23
24
24
25
pub use self :: StabilityLevel :: * ;
@@ -597,4 +598,93 @@ impl<'tcx> TyCtxt<'tcx> {
597
598
pub fn lookup_deprecation ( self , id : DefId ) -> Option < Deprecation > {
598
599
self . lookup_deprecation_entry ( id) . map ( |depr| depr. attr )
599
600
}
601
+
602
+ /// Returns true if `def_id` has an attribute that allows usage of the const unstable feature `feature_gate`.
603
+ pub fn rustc_allow_const_fn_unstable ( self , def_id : LocalDefId , feature_gate : Symbol ) -> bool {
604
+ let attrs = self . hir ( ) . attrs ( self . local_def_id_to_hir_id ( def_id) ) ;
605
+ attr:: rustc_allow_const_fn_unstable ( self . sess , attrs) . any ( |name| name == feature_gate)
606
+ }
607
+
608
+ pub fn enforce_trait_const_stability (
609
+ self ,
610
+ trait_def_id : DefId ,
611
+ span : Span ,
612
+ parent_def : Option < LocalDefId > ,
613
+ ) {
614
+ match self . lookup_const_stability ( trait_def_id) {
615
+ Some ( ConstStability {
616
+ level : attr:: StabilityLevel :: Unstable { implied_by : implied_feature, .. } ,
617
+ feature,
618
+ ..
619
+ } ) => {
620
+ let unstable_feature_allowed = span. allows_unstable ( feature)
621
+ || implied_feature. is_some_and ( |f| span. allows_unstable ( f) ) ;
622
+
623
+ let feature_enabled = trait_def_id. is_local ( )
624
+ || self . features ( ) . enabled ( feature)
625
+ || implied_feature. is_some_and ( |f| self . features ( ) . enabled ( f) ) ;
626
+
627
+ if !unstable_feature_allowed && !feature_enabled {
628
+ let mut diag = self . dcx ( ) . create_err ( crate :: error:: UnstableConstTrait {
629
+ span,
630
+ def_path : self . def_path_str ( trait_def_id) ,
631
+ } ) ;
632
+ self . disabled_nightly_features ( & mut diag, None , [ ( String :: new ( ) , feature) ] ) ;
633
+ diag. emit ( ) ;
634
+ } else if let Some ( parent) = parent_def {
635
+ // user either has enabled the feature or the unstable feature is allowed inside a macro,
636
+ // but if we consider the item we're in to be const stable, we should error as const stable
637
+ // items cannot use unstable features.
638
+ let is_stable = matches ! (
639
+ self . def_kind( parent) ,
640
+ DefKind :: AssocFn | DefKind :: Fn | DefKind :: Trait
641
+ ) && match self . lookup_const_stability ( parent) {
642
+ None => {
643
+ // `const fn`s without const stability attributes in a `staged_api` crate
644
+ // are implicitly stable.
645
+ self . features ( ) . staged_api ( )
646
+ }
647
+ Some ( stab) => {
648
+ // an explicitly stable `const fn`, or an unstable `const fn` that claims to not use any
649
+ // other unstably-const features with `const_stable_indirect`
650
+ stab. is_const_stable ( ) || stab. const_stable_indirect
651
+ }
652
+ } ;
653
+
654
+ // if our parent function is unstable, no need to error
655
+ if !is_stable {
656
+ return ;
657
+ }
658
+
659
+ // if the feature is explicitly allowed, don't error
660
+ if self . rustc_allow_const_fn_unstable ( parent, feature) {
661
+ return ;
662
+ }
663
+
664
+ emit_const_unstable_in_const_stable_exposed_error (
665
+ self , parent, span, feature, false ,
666
+ ) ;
667
+ }
668
+ }
669
+ _ => { }
670
+ }
671
+ }
672
+ }
673
+
674
+ pub fn emit_const_unstable_in_const_stable_exposed_error (
675
+ tcx : TyCtxt < ' _ > ,
676
+ def_id : LocalDefId ,
677
+ span : Span ,
678
+ gate : Symbol ,
679
+ is_function_call : bool ,
680
+ ) -> ErrorGuaranteed {
681
+ let attr_span = tcx. def_span ( def_id) . shrink_to_lo ( ) ;
682
+
683
+ tcx. dcx ( ) . emit_err ( crate :: error:: ConstUnstableInConstStableExposed {
684
+ gate : gate. to_string ( ) ,
685
+ span,
686
+ attr_span,
687
+ is_function_call,
688
+ is_function_call2 : is_function_call,
689
+ } )
600
690
}
0 commit comments