@@ -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 > =
@@ -470,6 +471,88 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
470
471
self . tcx . crate_level_attribute_injection_span ( self . tcx . local_def_id_to_hir_id ( id) )
471
472
} )
472
473
}
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
+ }
473
556
}
474
557
475
558
impl < ' tcx > Visitor < ' tcx > for Checker < ' _ , ' tcx > {
@@ -733,8 +816,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
733
816
span : * fn_span,
734
817
call_source,
735
818
} ) ;
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) ;
738
820
} else {
739
821
// Not even a const trait.
740
822
self . check_op ( ops:: FnCallNonConst {
@@ -810,7 +892,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
810
892
// fallback body is safe to expose on stable.
811
893
let is_const_stable = intrinsic. const_stable
812
894
|| ( !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) ) ;
814
896
match tcx. lookup_const_stability ( callee) {
815
897
None => {
816
898
// This doesn't need a separate const-stability check -- const-stability equals
@@ -859,83 +941,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
859
941
}
860
942
861
943
// 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) ;
939
945
}
940
946
941
947
// Forbid all `Drop` terminators unless the place being dropped is a local with no
0 commit comments