@@ -8,6 +8,7 @@ use std::ops::Deref;
88
99use rustc_attr_parsing:: { ConstStability , StabilityLevel } ;
1010use rustc_errors:: { Diag , ErrorGuaranteed } ;
11+ use rustc_hir:: def:: DefKind ;
1112use rustc_hir:: def_id:: DefId ;
1213use rustc_hir:: { self as hir, LangItem } ;
1314use rustc_index:: bit_set:: DenseBitSet ;
@@ -29,7 +30,7 @@ use super::ops::{self, NonConstOp, Status};
2930use super :: qualifs:: { self , HasMutInterior , NeedsDrop , NeedsNonConstDrop } ;
3031use super :: resolver:: FlowSensitiveAnalysis ;
3132use super :: { ConstCx , Qualif } ;
32- use crate :: check_consts:: is_safe_to_expose_on_stable_const_fn ;
33+ use crate :: check_consts:: is_fn_or_trait_safe_to_expose_on_stable ;
3334use crate :: errors;
3435
3536type QualifResults < ' mir , ' tcx , Q > =
@@ -470,6 +471,88 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
470471 self . tcx . crate_level_attribute_injection_span ( self . tcx . local_def_id_to_hir_id ( id) )
471472 } )
472473 }
474+
475+ /// Check the const stability of the given item (fn or trait).
476+ fn check_callee_stability ( & mut self , def_id : DefId ) {
477+ match self . tcx . lookup_const_stability ( def_id) {
478+ Some ( ConstStability { level : StabilityLevel :: Stable { .. } , .. } ) => {
479+ // All good.
480+ }
481+ None => {
482+ // This doesn't need a separate const-stability check -- const-stability equals
483+ // regular stability, and regular stability is checked separately.
484+ // However, we *do* have to worry about *recursive* const stability.
485+ if self . enforce_recursive_const_stability ( )
486+ && !is_fn_or_trait_safe_to_expose_on_stable ( self . tcx , def_id)
487+ {
488+ self . dcx ( ) . emit_err ( errors:: UnmarkedConstItemExposed {
489+ span : self . span ,
490+ def_path : self . tcx . def_path_str ( def_id) ,
491+ } ) ;
492+ }
493+ }
494+ Some ( ConstStability {
495+ level : StabilityLevel :: Unstable { implied_by : implied_feature, issue, .. } ,
496+ feature,
497+ ..
498+ } ) => {
499+ // An unstable const fn/trait with a feature gate.
500+ let callee_safe_to_expose_on_stable =
501+ is_fn_or_trait_safe_to_expose_on_stable ( self . tcx , def_id) ;
502+
503+ // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
504+ // the callee is safe to expose, to avoid bypassing recursive stability.
505+ // This is not ideal since it means the user sees an error, not the macro
506+ // author, but that's also the case if one forgets to set
507+ // `#[allow_internal_unstable]` in the first place. Note that this cannot be
508+ // integrated in the check below since we want to enforce
509+ // `callee_safe_to_expose_on_stable` even if
510+ // `!self.enforce_recursive_const_stability()`.
511+ if ( self . span . allows_unstable ( feature)
512+ || implied_feature. is_some_and ( |f| self . span . allows_unstable ( f) ) )
513+ && callee_safe_to_expose_on_stable
514+ {
515+ return ;
516+ }
517+
518+ // We can't use `check_op` to check whether the feature is enabled because
519+ // the logic is a bit different than elsewhere: local functions don't need
520+ // the feature gate, and there might be an "implied" gate that also suffices
521+ // to allow this.
522+ let feature_enabled = def_id. is_local ( )
523+ || self . tcx . features ( ) . enabled ( feature)
524+ || implied_feature. is_some_and ( |f| self . tcx . features ( ) . enabled ( f) )
525+ || {
526+ // When we're compiling the compiler itself we may pull in
527+ // crates from crates.io, but those crates may depend on other
528+ // crates also pulled in from crates.io. We want to ideally be
529+ // able to compile everything without requiring upstream
530+ // modifications, so in the case that this looks like a
531+ // `rustc_private` crate (e.g., a compiler crate) and we also have
532+ // the `-Z force-unstable-if-unmarked` flag present (we're
533+ // compiling a compiler crate), then let this missing feature
534+ // annotation slide.
535+ // This matches what we do in `eval_stability_allow_unstable` for
536+ // regular stability.
537+ feature == sym:: rustc_private
538+ && issue == NonZero :: new ( 27812 )
539+ && self . tcx . sess . opts . unstable_opts . force_unstable_if_unmarked
540+ } ;
541+ // Even if the feature is enabled, we still need check_op to double-check
542+ // this if the callee is not safe to expose on stable.
543+ if !feature_enabled || !callee_safe_to_expose_on_stable {
544+ self . check_op ( ops:: CallUnstable {
545+ def_id,
546+ feature,
547+ feature_enabled,
548+ safe_to_expose_on_stable : callee_safe_to_expose_on_stable,
549+ suggestion_span : self . crate_inject_span ( ) ,
550+ is_function_call : self . tcx . def_kind ( def_id) != DefKind :: Trait ,
551+ } ) ;
552+ }
553+ }
554+ }
555+ }
473556}
474557
475558impl < ' tcx > Visitor < ' tcx > for Checker < ' _ , ' tcx > {
@@ -733,8 +816,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
733816 span : * fn_span,
734817 call_source,
735818 } ) ;
736- // FIXME(const_trait_impl): do a more fine-grained check whether this
737- // particular trait can be const-stably called.
819+ self . check_callee_stability ( trait_did) ;
738820 } else {
739821 // Not even a const trait.
740822 self . check_op ( ops:: FnCallNonConst {
@@ -810,7 +892,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
810892 // fallback body is safe to expose on stable.
811893 let is_const_stable = intrinsic. const_stable
812894 || ( !intrinsic. must_be_overridden
813- && is_safe_to_expose_on_stable_const_fn ( tcx, callee) ) ;
895+ && is_fn_or_trait_safe_to_expose_on_stable ( tcx, callee) ) ;
814896 match tcx. lookup_const_stability ( callee) {
815897 None => {
816898 // This doesn't need a separate const-stability check -- const-stability equals
@@ -859,83 +941,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
859941 }
860942
861943 // Finally, stability for regular function calls -- this is the big one.
862- match tcx. lookup_const_stability ( callee) {
863- Some ( ConstStability { level : StabilityLevel :: Stable { .. } , .. } ) => {
864- // All good.
865- }
866- None => {
867- // This doesn't need a separate const-stability check -- const-stability equals
868- // regular stability, and regular stability is checked separately.
869- // However, we *do* have to worry about *recursive* const stability.
870- if self . enforce_recursive_const_stability ( )
871- && !is_safe_to_expose_on_stable_const_fn ( tcx, callee)
872- {
873- self . dcx ( ) . emit_err ( errors:: UnmarkedConstFnExposed {
874- span : self . span ,
875- def_path : self . tcx . def_path_str ( callee) ,
876- } ) ;
877- }
878- }
879- Some ( ConstStability {
880- level : StabilityLevel :: Unstable { implied_by : implied_feature, issue, .. } ,
881- feature,
882- ..
883- } ) => {
884- // An unstable const fn with a feature gate.
885- let callee_safe_to_expose_on_stable =
886- is_safe_to_expose_on_stable_const_fn ( tcx, callee) ;
887-
888- // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
889- // the callee is safe to expose, to avoid bypassing recursive stability.
890- // This is not ideal since it means the user sees an error, not the macro
891- // author, but that's also the case if one forgets to set
892- // `#[allow_internal_unstable]` in the first place. Note that this cannot be
893- // integrated in the check below since we want to enforce
894- // `callee_safe_to_expose_on_stable` even if
895- // `!self.enforce_recursive_const_stability()`.
896- if ( self . span . allows_unstable ( feature)
897- || implied_feature. is_some_and ( |f| self . span . allows_unstable ( f) ) )
898- && callee_safe_to_expose_on_stable
899- {
900- return ;
901- }
902-
903- // We can't use `check_op` to check whether the feature is enabled because
904- // the logic is a bit different than elsewhere: local functions don't need
905- // the feature gate, and there might be an "implied" gate that also suffices
906- // to allow this.
907- let feature_enabled = callee. is_local ( )
908- || tcx. features ( ) . enabled ( feature)
909- || implied_feature. is_some_and ( |f| tcx. features ( ) . enabled ( f) )
910- || {
911- // When we're compiling the compiler itself we may pull in
912- // crates from crates.io, but those crates may depend on other
913- // crates also pulled in from crates.io. We want to ideally be
914- // able to compile everything without requiring upstream
915- // modifications, so in the case that this looks like a
916- // `rustc_private` crate (e.g., a compiler crate) and we also have
917- // the `-Z force-unstable-if-unmarked` flag present (we're
918- // compiling a compiler crate), then let this missing feature
919- // annotation slide.
920- // This matches what we do in `eval_stability_allow_unstable` for
921- // regular stability.
922- feature == sym:: rustc_private
923- && issue == NonZero :: new ( 27812 )
924- && tcx. sess . opts . unstable_opts . force_unstable_if_unmarked
925- } ;
926- // Even if the feature is enabled, we still need check_op to double-check
927- // this if the callee is not safe to expose on stable.
928- if !feature_enabled || !callee_safe_to_expose_on_stable {
929- self . check_op ( ops:: FnCallUnstable {
930- def_id : callee,
931- feature,
932- feature_enabled,
933- safe_to_expose_on_stable : callee_safe_to_expose_on_stable,
934- suggestion_span : self . crate_inject_span ( ) ,
935- } ) ;
936- }
937- }
938- }
944+ self . check_callee_stability ( callee) ;
939945 }
940946
941947 // Forbid all `Drop` terminators unless the place being dropped is a local with no
0 commit comments