@@ -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
@@ -844,42 +849,95 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
844
849
} ,
845
850
) ;
846
851
847
- let is_allowed_through_unstable_modules = |def_id| {
848
- self . tcx . lookup_stability ( def_id) . is_some_and ( |stab| match stab. level {
849
- StabilityLevel :: Stable { allowed_through_unstable_modules, .. } => {
850
- allowed_through_unstable_modules
852
+ if item_is_allowed {
853
+ // The item itself is allowed; check whether the path there is also allowed.
854
+ let is_allowed_through_unstable_modules: Option < AllowedThroughUnstableModules > =
855
+ self . tcx . lookup_stability ( def_id) . and_then ( |stab| match stab. level {
856
+ StabilityLevel :: Stable { allowed_through_unstable_modules, .. } => {
857
+ allowed_through_unstable_modules
858
+ }
859
+ _ => None ,
860
+ } ) ;
861
+
862
+ if is_allowed_through_unstable_modules. is_none ( ) {
863
+ // Check parent modules stability as well if the item the path refers to is itself
864
+ // stable. We only emit warnings for unstable path segments if the item is stable
865
+ // or allowed because stability is often inherited, so the most common case is that
866
+ // both the segments and the item are unstable behind the same feature flag.
867
+ //
868
+ // We check here rather than in `visit_path_segment` to prevent visiting the last
869
+ // path segment twice
870
+ //
871
+ // We include special cases via #[rustc_allowed_through_unstable_modules] for items
872
+ // that were accidentally stabilized through unstable paths before this check was
873
+ // added, such as `core::intrinsics::transmute`
874
+ let parents = path. segments . iter ( ) . rev ( ) . skip ( 1 ) ;
875
+ for path_segment in parents {
876
+ if let Some ( def_id) = path_segment. res . opt_def_id ( ) {
877
+ // use `None` for id to prevent deprecation check
878
+ self . tcx . check_stability_allow_unstable (
879
+ def_id,
880
+ None ,
881
+ path. span ,
882
+ None ,
883
+ if is_unstable_reexport ( self . tcx , id) {
884
+ AllowUnstable :: Yes
885
+ } else {
886
+ AllowUnstable :: No
887
+ } ,
888
+ ) ;
889
+ }
851
890
}
852
- _ => false ,
853
- } )
854
- } ;
855
-
856
- if item_is_allowed && !is_allowed_through_unstable_modules ( def_id) {
857
- // Check parent modules stability as well if the item the path refers to is itself
858
- // stable. We only emit warnings for unstable path segments if the item is stable
859
- // or allowed because stability is often inherited, so the most common case is that
860
- // both the segments and the item are unstable behind the same feature flag.
861
- //
862
- // We check here rather than in `visit_path_segment` to prevent visiting the last
863
- // path segment twice
864
- //
865
- // We include special cases via #[rustc_allowed_through_unstable_modules] for items
866
- // that were accidentally stabilized through unstable paths before this check was
867
- // added, such as `core::intrinsics::transmute`
868
- let parents = path. segments . iter ( ) . rev ( ) . skip ( 1 ) ;
869
- for path_segment in parents {
870
- if let Some ( def_id) = path_segment. res . opt_def_id ( ) {
871
- // use `None` for id to prevent deprecation check
872
- self . tcx . check_stability_allow_unstable (
873
- def_id,
874
- None ,
875
- path. span ,
876
- None ,
877
- if is_unstable_reexport ( self . tcx , id) {
878
- AllowUnstable :: Yes
879
- } else {
880
- AllowUnstable :: No
881
- } ,
882
- ) ;
891
+ } else if let Some ( AllowedThroughUnstableModules :: WithDeprecation ( deprecation) ) =
892
+ is_allowed_through_unstable_modules
893
+ {
894
+ // Similar to above, but we cannot use `check_stability_allow_unstable` as that would
895
+ // immediately show the stability error. We just want to know the result and disaplay
896
+ // our own kind of error.
897
+ let parents = path. segments . iter ( ) . rev ( ) . skip ( 1 ) ;
898
+ for path_segment in parents {
899
+ if let Some ( def_id) = path_segment. res . opt_def_id ( ) {
900
+ // use `None` for id to prevent deprecation check
901
+ let eval_result = self . tcx . eval_stability_allow_unstable (
902
+ def_id,
903
+ None ,
904
+ path. span ,
905
+ None ,
906
+ if is_unstable_reexport ( self . tcx , id) {
907
+ AllowUnstable :: Yes
908
+ } else {
909
+ AllowUnstable :: No
910
+ } ,
911
+ ) ;
912
+ let is_allowed = matches ! ( eval_result, EvalResult :: Allow ) ;
913
+ if !is_allowed {
914
+ // Calculating message for lint involves calling `self.def_path_str`,
915
+ // which will by default invoke the expensive `visible_parent_map` query.
916
+ // Skip all that work if the lint is allowed anyway.
917
+ if self . tcx . lint_level_at_node ( DEPRECATED , id) . 0
918
+ == lint:: Level :: Allow
919
+ {
920
+ return ;
921
+ }
922
+ // Show a deprecation message.
923
+ let def_path =
924
+ with_no_trimmed_paths ! ( self . tcx. def_path_str( def_id) ) ;
925
+ let def_kind = self . tcx . def_descr ( def_id) ;
926
+ let diag = Deprecated {
927
+ sub : None ,
928
+ kind : def_kind. to_owned ( ) ,
929
+ path : def_path,
930
+ note : Some ( deprecation) ,
931
+ since_kind : lint:: DeprecatedSinceKind :: InEffect ,
932
+ } ;
933
+ self . tcx . emit_node_span_lint (
934
+ DEPRECATED ,
935
+ id,
936
+ method_span. unwrap_or ( path. span ) ,
937
+ diag,
938
+ ) ;
939
+ }
940
+ }
883
941
}
884
942
}
885
943
}
0 commit comments