@@ -5,8 +5,8 @@ use std::mem::replace;
55use std:: num:: NonZero ;
66
77use 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 ,
1010} ;
1111use rustc_data_structures:: fx:: FxIndexMap ;
1212use rustc_data_structures:: unord:: { ExtendUnord , UnordMap , UnordSet } ;
@@ -20,11 +20,16 @@ use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
2020use rustc_middle:: hir:: nested_filter;
2121use rustc_middle:: middle:: lib_features:: { FeatureStability , LibFeatures } ;
2222use 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+ } ;
2426use rustc_middle:: query:: Providers ;
2527use rustc_middle:: ty:: TyCtxt ;
28+ use rustc_middle:: ty:: print:: with_no_trimmed_paths;
2629use 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+ } ;
2833use rustc_span:: { Span , Symbol , sym} ;
2934use tracing:: { debug, info} ;
3035
@@ -874,42 +879,95 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
874879 } ,
875880 ) ;
876881
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+ }
881920 }
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+ }
913971 }
914972 }
915973 }
0 commit comments