@@ -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