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