@@ -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,90 @@ 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
+ let Some ( ConstStability {
615
+ level : attr:: StabilityLevel :: Unstable { implied_by : implied_feature, .. } ,
616
+ feature,
617
+ ..
618
+ } ) = self . lookup_const_stability ( trait_def_id)
619
+ else {
620
+ return ;
621
+ } ;
622
+
623
+ let unstable_feature_allowed = span. allows_unstable ( feature)
624
+ || implied_feature. is_some_and ( |f| span. allows_unstable ( f) ) ;
625
+
626
+ let feature_enabled = trait_def_id. is_local ( )
627
+ || self . features ( ) . enabled ( feature)
628
+ || implied_feature. is_some_and ( |f| self . features ( ) . enabled ( f) ) ;
629
+
630
+ if !unstable_feature_allowed && !feature_enabled {
631
+ let mut diag = self . dcx ( ) . create_err ( crate :: error:: UnstableConstTrait {
632
+ span,
633
+ def_path : self . def_path_str ( trait_def_id) ,
634
+ } ) ;
635
+ self . disabled_nightly_features ( & mut diag, None , [ ( String :: new ( ) , feature) ] ) ;
636
+ diag. emit ( ) ;
637
+ } else if let Some ( parent) = parent_def {
638
+ // user either has enabled the feature or the unstable feature is allowed inside a macro,
639
+ // but if we consider the item we're in to be const stable, we should error as const stable
640
+ // items cannot use unstable features.
641
+ let is_stable =
642
+ matches ! ( self . def_kind( parent) , DefKind :: AssocFn | DefKind :: Fn | DefKind :: Trait )
643
+ && match self . lookup_const_stability ( parent) {
644
+ None => {
645
+ // `const fn`s without const stability attributes in a `staged_api` crate
646
+ // are implicitly stable.
647
+ self . features ( ) . staged_api ( )
648
+ }
649
+ Some ( stab) => {
650
+ // an explicitly stable `const fn`, or an unstable `const fn` that claims to not use any
651
+ // other unstably-const features with `const_stable_indirect`
652
+ stab. is_const_stable ( ) || stab. const_stable_indirect
653
+ }
654
+ } ;
655
+
656
+ // if our parent function is unstable, no need to error
657
+ if !is_stable {
658
+ return ;
659
+ }
660
+
661
+ // if the feature is explicitly allowed, don't error
662
+ if self . rustc_allow_const_fn_unstable ( parent, feature) {
663
+ return ;
664
+ }
665
+
666
+ emit_const_unstable_in_const_stable_exposed_error ( self , parent, span, feature, false ) ;
667
+ }
668
+ }
669
+ }
670
+
671
+ pub fn emit_const_unstable_in_const_stable_exposed_error (
672
+ tcx : TyCtxt < ' _ > ,
673
+ def_id : LocalDefId ,
674
+ span : Span ,
675
+ gate : Symbol ,
676
+ is_function_call : bool ,
677
+ ) -> ErrorGuaranteed {
678
+ let attr_span = tcx. def_span ( def_id) . shrink_to_lo ( ) ;
679
+
680
+ tcx. dcx ( ) . emit_err ( crate :: error:: ConstUnstableInConstStableExposed {
681
+ gate : gate. to_string ( ) ,
682
+ span,
683
+ attr_span,
684
+ is_function_call,
685
+ is_function_call2 : is_function_call,
686
+ } )
600
687
}
0 commit comments