@@ -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:: { ErrorGuaranteed , Span , Symbol , sym} ;
2223use tracing:: debug;
2324
2425pub use self :: StabilityLevel :: * ;
@@ -597,4 +598,90 @@ 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 ( 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+ } )
600687}
0 commit comments