@@ -5,8 +5,8 @@ use std::mem::replace;
5
5
use std:: num:: NonZero ;
6
6
7
7
use rustc_attr_parsing:: {
8
- self as attr, ConstStability , DeprecatedSince , Stability , StabilityLevel , StableSince ,
9
- UnstableReason , VERSION_PLACEHOLDER ,
8
+ self as attr, AllowedThroughUnstableModules , ConstStability , DeprecatedSince , Stability ,
9
+ StabilityLevel , StableSince , UnstableReason , VERSION_PLACEHOLDER ,
10
10
} ;
11
11
use rustc_data_structures:: fx:: FxIndexMap ;
12
12
use rustc_data_structures:: unord:: { ExtendUnord , UnordMap , UnordSet } ;
@@ -20,11 +20,16 @@ use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
20
20
use rustc_middle:: hir:: nested_filter;
21
21
use rustc_middle:: middle:: lib_features:: { FeatureStability , LibFeatures } ;
22
22
use rustc_middle:: middle:: privacy:: EffectiveVisibilities ;
23
- use rustc_middle:: middle:: stability:: { AllowUnstable , DeprecationEntry , Index } ;
23
+ use rustc_middle:: middle:: stability:: {
24
+ AllowUnstable , Deprecated , DeprecationEntry , EvalResult , Index ,
25
+ } ;
24
26
use rustc_middle:: query:: Providers ;
25
27
use rustc_middle:: ty:: TyCtxt ;
28
+ use rustc_middle:: ty:: print:: with_no_trimmed_paths;
26
29
use rustc_session:: lint;
27
- use rustc_session:: lint:: builtin:: { INEFFECTIVE_UNSTABLE_TRAIT_IMPL , USELESS_DEPRECATED } ;
30
+ use rustc_session:: lint:: builtin:: {
31
+ DEPRECATED , INEFFECTIVE_UNSTABLE_TRAIT_IMPL , USELESS_DEPRECATED ,
32
+ } ;
28
33
use rustc_span:: { Span , Symbol , sym} ;
29
34
use tracing:: { debug, info} ;
30
35
@@ -874,42 +879,95 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
874
879
} ,
875
880
) ;
876
881
877
- let is_allowed_through_unstable_modules = |def_id| {
878
- self . tcx . lookup_stability ( def_id) . is_some_and ( |stab| match stab. level {
879
- StabilityLevel :: Stable { allowed_through_unstable_modules, .. } => {
880
- allowed_through_unstable_modules
882
+ if item_is_allowed {
883
+ // The item itself is allowed; check whether the path there is also allowed.
884
+ let is_allowed_through_unstable_modules: Option < AllowedThroughUnstableModules > =
885
+ self . tcx . lookup_stability ( def_id) . and_then ( |stab| match stab. level {
886
+ StabilityLevel :: Stable { allowed_through_unstable_modules, .. } => {
887
+ allowed_through_unstable_modules
888
+ }
889
+ _ => None ,
890
+ } ) ;
891
+
892
+ if is_allowed_through_unstable_modules. is_none ( ) {
893
+ // Check parent modules stability as well if the item the path refers to is itself
894
+ // stable. We only emit warnings for unstable path segments if the item is stable
895
+ // or allowed because stability is often inherited, so the most common case is that
896
+ // both the segments and the item are unstable behind the same feature flag.
897
+ //
898
+ // We check here rather than in `visit_path_segment` to prevent visiting the last
899
+ // path segment twice
900
+ //
901
+ // We include special cases via #[rustc_allowed_through_unstable_modules] for items
902
+ // that were accidentally stabilized through unstable paths before this check was
903
+ // added, such as `core::intrinsics::transmute`
904
+ let parents = path. segments . iter ( ) . rev ( ) . skip ( 1 ) ;
905
+ for path_segment in parents {
906
+ if let Some ( def_id) = path_segment. res . opt_def_id ( ) {
907
+ // use `None` for id to prevent deprecation check
908
+ self . tcx . check_stability_allow_unstable (
909
+ def_id,
910
+ None ,
911
+ path. span ,
912
+ None ,
913
+ if is_unstable_reexport ( self . tcx , id) {
914
+ AllowUnstable :: Yes
915
+ } else {
916
+ AllowUnstable :: No
917
+ } ,
918
+ ) ;
919
+ }
881
920
}
882
- _ => false ,
883
- } )
884
- } ;
885
-
886
- if item_is_allowed && !is_allowed_through_unstable_modules ( def_id) {
887
- // Check parent modules stability as well if the item the path refers to is itself
888
- // stable. We only emit warnings for unstable path segments if the item is stable
889
- // or allowed because stability is often inherited, so the most common case is that
890
- // both the segments and the item are unstable behind the same feature flag.
891
- //
892
- // We check here rather than in `visit_path_segment` to prevent visiting the last
893
- // path segment twice
894
- //
895
- // We include special cases via #[rustc_allowed_through_unstable_modules] for items
896
- // that were accidentally stabilized through unstable paths before this check was
897
- // added, such as `core::intrinsics::transmute`
898
- let parents = path. segments . iter ( ) . rev ( ) . skip ( 1 ) ;
899
- for path_segment in parents {
900
- if let Some ( def_id) = path_segment. res . opt_def_id ( ) {
901
- // use `None` for id to prevent deprecation check
902
- self . tcx . check_stability_allow_unstable (
903
- def_id,
904
- None ,
905
- path. span ,
906
- None ,
907
- if is_unstable_reexport ( self . tcx , id) {
908
- AllowUnstable :: Yes
909
- } else {
910
- AllowUnstable :: No
911
- } ,
912
- ) ;
921
+ } else if let Some ( AllowedThroughUnstableModules :: WithDeprecation ( deprecation) ) =
922
+ is_allowed_through_unstable_modules
923
+ {
924
+ // Similar to above, but we cannot use `check_stability_allow_unstable` as that would
925
+ // immediately show the stability error. We just want to know the result and disaplay
926
+ // our own kind of error.
927
+ let parents = path. segments . iter ( ) . rev ( ) . skip ( 1 ) ;
928
+ for path_segment in parents {
929
+ if let Some ( def_id) = path_segment. res . opt_def_id ( ) {
930
+ // use `None` for id to prevent deprecation check
931
+ let eval_result = self . tcx . eval_stability_allow_unstable (
932
+ def_id,
933
+ None ,
934
+ path. span ,
935
+ None ,
936
+ if is_unstable_reexport ( self . tcx , id) {
937
+ AllowUnstable :: Yes
938
+ } else {
939
+ AllowUnstable :: No
940
+ } ,
941
+ ) ;
942
+ let is_allowed = matches ! ( eval_result, EvalResult :: Allow ) ;
943
+ if !is_allowed {
944
+ // Calculating message for lint involves calling `self.def_path_str`,
945
+ // which will by default invoke the expensive `visible_parent_map` query.
946
+ // Skip all that work if the lint is allowed anyway.
947
+ if self . tcx . lint_level_at_node ( DEPRECATED , id) . 0
948
+ == lint:: Level :: Allow
949
+ {
950
+ return ;
951
+ }
952
+ // Show a deprecation message.
953
+ let def_path =
954
+ with_no_trimmed_paths ! ( self . tcx. def_path_str( def_id) ) ;
955
+ let def_kind = self . tcx . def_descr ( def_id) ;
956
+ let diag = Deprecated {
957
+ sub : None ,
958
+ kind : def_kind. to_owned ( ) ,
959
+ path : def_path,
960
+ note : Some ( deprecation) ,
961
+ since_kind : lint:: DeprecatedSinceKind :: InEffect ,
962
+ } ;
963
+ self . tcx . emit_node_span_lint (
964
+ DEPRECATED ,
965
+ id,
966
+ method_span. unwrap_or ( path. span ) ,
967
+ diag,
968
+ ) ;
969
+ }
970
+ }
913
971
}
914
972
}
915
973
}
0 commit comments