@@ -8,6 +8,7 @@ use std::ops::Deref;
8
8
9
9
use rustc_attr_parsing:: { ConstStability , StabilityLevel } ;
10
10
use rustc_errors:: { Diag , ErrorGuaranteed } ;
11
+ use rustc_hir:: def:: DefKind ;
11
12
use rustc_hir:: def_id:: DefId ;
12
13
use rustc_hir:: { self as hir, LangItem } ;
13
14
use rustc_index:: bit_set:: DenseBitSet ;
@@ -29,7 +30,7 @@ use super::ops::{self, NonConstOp, Status};
29
30
use super :: qualifs:: { self , HasMutInterior , NeedsDrop , NeedsNonConstDrop } ;
30
31
use super :: resolver:: FlowSensitiveAnalysis ;
31
32
use 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 ;
33
34
use crate :: errors;
34
35
35
36
type QualifResults < ' mir , ' tcx , Q > =
@@ -694,6 +695,87 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
694
695
}
695
696
} ;
696
697
698
+ let check_stability = |this : & mut Self , def_id| {
699
+ match tcx. lookup_const_stability ( def_id) {
700
+ Some ( ConstStability { level : StabilityLevel :: Stable { .. } , .. } ) => {
701
+ // All good.
702
+ }
703
+ None => {
704
+ // This doesn't need a separate const-stability check -- const-stability equals
705
+ // regular stability, and regular stability is checked separately.
706
+ // However, we *do* have to worry about *recursive* const stability.
707
+ if this. enforce_recursive_const_stability ( )
708
+ && !is_fn_or_trait_safe_to_expose_on_stable ( tcx, def_id)
709
+ {
710
+ this. dcx ( ) . emit_err ( errors:: UnmarkedConstItemExposed {
711
+ span : this. span ,
712
+ def_path : this. tcx . def_path_str ( def_id) ,
713
+ } ) ;
714
+ }
715
+ }
716
+ Some ( ConstStability {
717
+ level : StabilityLevel :: Unstable { implied_by : implied_feature, issue, .. } ,
718
+ feature,
719
+ ..
720
+ } ) => {
721
+ // An unstable const fn/trait with a feature gate.
722
+ let callee_safe_to_expose_on_stable =
723
+ is_fn_or_trait_safe_to_expose_on_stable ( tcx, def_id) ;
724
+
725
+ // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
726
+ // the callee is safe to expose, to avoid bypassing recursive stability.
727
+ // This is not ideal since it means the user sees an error, not the macro
728
+ // author, but that's also the case if one forgets to set
729
+ // `#[allow_internal_unstable]` in the first place. Note that this cannot be
730
+ // integrated in the check below since we want to enforce
731
+ // `callee_safe_to_expose_on_stable` even if
732
+ // `!self.enforce_recursive_const_stability()`.
733
+ if ( this. span . allows_unstable ( feature)
734
+ || implied_feature. is_some_and ( |f| this. span . allows_unstable ( f) ) )
735
+ && callee_safe_to_expose_on_stable
736
+ {
737
+ return ;
738
+ }
739
+
740
+ // We can't use `check_op` to check whether the feature is enabled because
741
+ // the logic is a bit different than elsewhere: local functions don't need
742
+ // the feature gate, and there might be an "implied" gate that also suffices
743
+ // to allow this.
744
+ let feature_enabled = def_id. is_local ( )
745
+ || tcx. features ( ) . enabled ( feature)
746
+ || implied_feature. is_some_and ( |f| tcx. features ( ) . enabled ( f) )
747
+ || {
748
+ // When we're compiling the compiler itself we may pull in
749
+ // crates from crates.io, but those crates may depend on other
750
+ // crates also pulled in from crates.io. We want to ideally be
751
+ // able to compile everything without requiring upstream
752
+ // modifications, so in the case that this looks like a
753
+ // `rustc_private` crate (e.g., a compiler crate) and we also have
754
+ // the `-Z force-unstable-if-unmarked` flag present (we're
755
+ // compiling a compiler crate), then let this missing feature
756
+ // annotation slide.
757
+ // This matches what we do in `eval_stability_allow_unstable` for
758
+ // regular stability.
759
+ feature == sym:: rustc_private
760
+ && issue == NonZero :: new ( 27812 )
761
+ && tcx. sess . opts . unstable_opts . force_unstable_if_unmarked
762
+ } ;
763
+ // Even if the feature is enabled, we still need check_op to double-check
764
+ // this if the callee is not safe to expose on stable.
765
+ if !feature_enabled || !callee_safe_to_expose_on_stable {
766
+ this. check_op ( ops:: CallUnstable {
767
+ def_id,
768
+ feature,
769
+ feature_enabled,
770
+ safe_to_expose_on_stable : callee_safe_to_expose_on_stable,
771
+ suggestion_span : this. crate_inject_span ( ) ,
772
+ is_function_call : tcx. def_kind ( def_id) != DefKind :: Trait ,
773
+ } ) ;
774
+ }
775
+ }
776
+ }
777
+ } ;
778
+
697
779
let has_const_conditions =
698
780
self . revalidate_conditional_constness ( callee, fn_args, * fn_span) ;
699
781
@@ -716,8 +798,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
716
798
span : * fn_span,
717
799
call_source,
718
800
} ) ;
719
- // FIXME(const_trait_impl): do a more fine-grained check whether this
720
- // particular trait can be const-stably called.
801
+ check_stability ( self , trait_did) ;
721
802
} else {
722
803
// Not even a const trait.
723
804
self . check_op ( ops:: FnCallNonConst {
@@ -793,7 +874,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
793
874
// fallback body is safe to expose on stable.
794
875
let is_const_stable = intrinsic. const_stable
795
876
|| ( !intrinsic. must_be_overridden
796
- && is_safe_to_expose_on_stable_const_fn ( tcx, callee) ) ;
877
+ && is_fn_or_trait_safe_to_expose_on_stable ( tcx, callee) ) ;
797
878
match tcx. lookup_const_stability ( callee) {
798
879
None => {
799
880
// This doesn't need a separate const-stability check -- const-stability equals
@@ -842,83 +923,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
842
923
}
843
924
844
925
// 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
- }
926
+ check_stability ( self , callee)
922
927
}
923
928
924
929
// Forbid all `Drop` terminators unless the place being dropped is a local with no
0 commit comments