@@ -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
+ // This should work pretty much exactly like the function stability logic in
615
+ // `compiler/rustc_const_eval/src/check_consts/check.rs`.
616
+ // FIXME: Find some way to not duplicate that logic.
617
+ let Some ( ConstStability {
618
+ level : attr:: StabilityLevel :: Unstable { implied_by : implied_feature, .. } ,
619
+ feature,
620
+ ..
621
+ } ) = self . lookup_const_stability ( trait_def_id)
622
+ else {
623
+ return ;
624
+ } ;
625
+
626
+ let unstable_feature_allowed = span. allows_unstable ( feature)
627
+ || implied_feature. is_some_and ( |f| span. allows_unstable ( f) ) ;
628
+
629
+ let feature_enabled = trait_def_id. is_local ( )
630
+ || self . features ( ) . enabled ( feature)
631
+ || implied_feature. is_some_and ( |f| self . features ( ) . enabled ( f) ) ;
632
+
633
+ if !unstable_feature_allowed && !feature_enabled {
634
+ let mut diag = self . dcx ( ) . create_err ( crate :: error:: UnstableConstTrait {
635
+ span,
636
+ def_path : self . def_path_str ( trait_def_id) ,
637
+ } ) ;
638
+ self . disabled_nightly_features ( & mut diag, None , [ ( String :: new ( ) , feature) ] ) ;
639
+ diag. emit ( ) ;
640
+ } else if let Some ( parent) = parent_def {
641
+ // user either has enabled the feature or the unstable feature is allowed inside a macro,
642
+ // but if we consider the item we're in to be const stable, we should error as const stable
643
+ // items cannot use unstable features.
644
+ let is_stable =
645
+ matches ! ( self . def_kind( parent) , DefKind :: AssocFn | DefKind :: Fn | DefKind :: Trait )
646
+ && match self . lookup_const_stability ( parent) {
647
+ None => {
648
+ // `const fn`s without const stability attributes in a `staged_api` crate
649
+ // are implicitly stable.
650
+ self . features ( ) . staged_api ( )
651
+ }
652
+ Some ( stab) => {
653
+ // an explicitly stable `const fn`, or an unstable `const fn` that claims to not use any
654
+ // other unstably-const features with `const_stable_indirect`
655
+ stab. is_const_stable ( ) || stab. const_stable_indirect
656
+ }
657
+ } ;
658
+
659
+ // if our parent function is unstable, no need to error
660
+ if !is_stable {
661
+ return ;
662
+ }
663
+
664
+ // if the feature is explicitly allowed, don't error
665
+ if self . rustc_allow_const_fn_unstable ( parent, feature) {
666
+ return ;
667
+ }
668
+
669
+ emit_const_unstable_in_const_stable_exposed_error ( self , parent, span, feature, false ) ;
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