@@ -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
@@ -844,42 +849,95 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
844849 } ,
845850 ) ;
846851
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+ }
851890 }
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+ }
883941 }
884942 }
885943 }
0 commit comments