@@ -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 > {
@@ -716,8 +799,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
716799 span : * fn_span,
717800 call_source,
718801 } ) ;
719- // FIXME(const_trait_impl): do a more fine-grained check whether this
720- // particular trait can be const-stably called.
802+ self . check_callee_stability ( trait_did) ;
721803 } else {
722804 // Not even a const trait.
723805 self . check_op ( ops:: FnCallNonConst {
@@ -793,7 +875,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
793875 // fallback body is safe to expose on stable.
794876 let is_const_stable = intrinsic. const_stable
795877 || ( !intrinsic. must_be_overridden
796- && is_safe_to_expose_on_stable_const_fn ( tcx, callee) ) ;
878+ && is_fn_or_trait_safe_to_expose_on_stable ( tcx, callee) ) ;
797879 match tcx. lookup_const_stability ( callee) {
798880 None => {
799881 // This doesn't need a separate const-stability check -- const-stability equals
@@ -842,83 +924,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
842924 }
843925
844926 // Finally, stability for regular function calls -- this is the big one.
845- match tcx. lookup_const_stability ( callee) {
846- Some ( ConstStability { level : StabilityLevel :: Stable { .. } , .. } ) => {
847- // All good.
848- }
849- None => {
850- // This doesn't need a separate const-stability check -- const-stability equals
851- // regular stability, and regular stability is checked separately.
852- // However, we *do* have to worry about *recursive* const stability.
853- if self . enforce_recursive_const_stability ( )
854- && !is_safe_to_expose_on_stable_const_fn ( tcx, callee)
855- {
856- self . dcx ( ) . emit_err ( errors:: UnmarkedConstFnExposed {
857- span : self . span ,
858- def_path : self . tcx . def_path_str ( callee) ,
859- } ) ;
860- }
861- }
862- Some ( ConstStability {
863- level : StabilityLevel :: Unstable { implied_by : implied_feature, issue, .. } ,
864- feature,
865- ..
866- } ) => {
867- // An unstable const fn with a feature gate.
868- let callee_safe_to_expose_on_stable =
869- is_safe_to_expose_on_stable_const_fn ( tcx, callee) ;
870-
871- // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
872- // the callee is safe to expose, to avoid bypassing recursive stability.
873- // This is not ideal since it means the user sees an error, not the macro
874- // author, but that's also the case if one forgets to set
875- // `#[allow_internal_unstable]` in the first place. Note that this cannot be
876- // integrated in the check below since we want to enforce
877- // `callee_safe_to_expose_on_stable` even if
878- // `!self.enforce_recursive_const_stability()`.
879- if ( self . span . allows_unstable ( feature)
880- || implied_feature. is_some_and ( |f| self . span . allows_unstable ( f) ) )
881- && callee_safe_to_expose_on_stable
882- {
883- return ;
884- }
885-
886- // We can't use `check_op` to check whether the feature is enabled because
887- // the logic is a bit different than elsewhere: local functions don't need
888- // the feature gate, and there might be an "implied" gate that also suffices
889- // to allow this.
890- let feature_enabled = callee. is_local ( )
891- || tcx. features ( ) . enabled ( feature)
892- || implied_feature. is_some_and ( |f| tcx. features ( ) . enabled ( f) )
893- || {
894- // When we're compiling the compiler itself we may pull in
895- // crates from crates.io, but those crates may depend on other
896- // crates also pulled in from crates.io. We want to ideally be
897- // able to compile everything without requiring upstream
898- // modifications, so in the case that this looks like a
899- // `rustc_private` crate (e.g., a compiler crate) and we also have
900- // the `-Z force-unstable-if-unmarked` flag present (we're
901- // compiling a compiler crate), then let this missing feature
902- // annotation slide.
903- // This matches what we do in `eval_stability_allow_unstable` for
904- // regular stability.
905- feature == sym:: rustc_private
906- && issue == NonZero :: new ( 27812 )
907- && tcx. sess . opts . unstable_opts . force_unstable_if_unmarked
908- } ;
909- // Even if the feature is enabled, we still need check_op to double-check
910- // this if the callee is not safe to expose on stable.
911- if !feature_enabled || !callee_safe_to_expose_on_stable {
912- self . check_op ( ops:: FnCallUnstable {
913- def_id : callee,
914- feature,
915- feature_enabled,
916- safe_to_expose_on_stable : callee_safe_to_expose_on_stable,
917- suggestion_span : self . crate_inject_span ( ) ,
918- } ) ;
919- }
920- }
921- }
927+ self . check_callee_stability ( callee) ;
922928 }
923929
924930 // Forbid all `Drop` terminators unless the place being dropped is a local with no
0 commit comments