|
2 | 2 | //! propagating default levels lexically from parent to children ast nodes. |
3 | 3 |
|
4 | 4 | use attr::StabilityLevel; |
5 | | -use rustc_attr::{self as attr, ConstStability, Stability}; |
| 5 | +use rustc_attr::{self as attr, ConstStability, Stability, Unstable}; |
6 | 6 | use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; |
7 | | -use rustc_errors::struct_span_err; |
| 7 | +use rustc_errors::{struct_span_err, Applicability}; |
8 | 8 | use rustc_hir as hir; |
9 | 9 | use rustc_hir::def::{DefKind, Res}; |
10 | 10 | use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; |
@@ -265,6 +265,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { |
265 | 265 | } |
266 | 266 | } |
267 | 267 |
|
| 268 | + if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab { |
| 269 | + self.index.implications.insert(implied_by, feature); |
| 270 | + } |
| 271 | + |
268 | 272 | self.index.stab_map.insert(def_id, stab); |
269 | 273 | stab |
270 | 274 | }); |
@@ -610,6 +614,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { |
610 | 614 | stab_map: Default::default(), |
611 | 615 | const_stab_map: Default::default(), |
612 | 616 | depr_map: Default::default(), |
| 617 | + implications: Default::default(), |
613 | 618 | }; |
614 | 619 |
|
615 | 620 | { |
@@ -668,6 +673,7 @@ pub(crate) fn provide(providers: &mut Providers) { |
668 | 673 | *providers = Providers { |
669 | 674 | check_mod_unstable_api_usage, |
670 | 675 | stability_index, |
| 676 | + stability_implications: |tcx, _| tcx.stability().implications.clone(), |
671 | 677 | lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), |
672 | 678 | lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), |
673 | 679 | lookup_deprecation_entry: |tcx, id| { |
@@ -946,11 +952,18 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { |
946 | 952 | remaining_lib_features.remove(&sym::libc); |
947 | 953 | remaining_lib_features.remove(&sym::test); |
948 | 954 |
|
| 955 | + let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone(); |
| 956 | + for &cnum in tcx.crates(()) { |
| 957 | + implications.extend(tcx.stability_implications(cnum)); |
| 958 | + } |
| 959 | + |
949 | 960 | let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| { |
950 | 961 | for &(feature, since) in defined_features { |
951 | | - if let Some(since) = since { |
952 | | - if let Some(span) = remaining_lib_features.get(&feature) { |
953 | | - // Warn if the user has enabled an already-stable lib feature. |
| 962 | + if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) { |
| 963 | + // Warn if the user has enabled an already-stable lib feature. |
| 964 | + if let Some(implies) = implications.get(&feature) { |
| 965 | + unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since); |
| 966 | + } else { |
954 | 967 | unnecessary_stable_feature_lint(tcx, *span, feature, since); |
955 | 968 | } |
956 | 969 | } |
@@ -983,12 +996,41 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { |
983 | 996 | // don't lint about unused features. We should re-enable this one day! |
984 | 997 | } |
985 | 998 |
|
| 999 | +fn unnecessary_partially_stable_feature_lint( |
| 1000 | + tcx: TyCtxt<'_>, |
| 1001 | + span: Span, |
| 1002 | + feature: Symbol, |
| 1003 | + implies: Symbol, |
| 1004 | + since: Symbol, |
| 1005 | +) { |
| 1006 | + tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { |
| 1007 | + lint.build(&format!( |
| 1008 | + "the feature `{feature}` has been partially stabilized since {since} and is succeeded \ |
| 1009 | + by the feature `{implies}`" |
| 1010 | + )) |
| 1011 | + .span_suggestion( |
| 1012 | + span, |
| 1013 | + &format!( |
| 1014 | + "if you are using features which are still unstable, change to using `{implies}`" |
| 1015 | + ), |
| 1016 | + implies, |
| 1017 | + Applicability::MaybeIncorrect, |
| 1018 | + ) |
| 1019 | + .span_suggestion( |
| 1020 | + tcx.sess.source_map().span_extend_to_line(span), |
| 1021 | + "if you are using features which are now stable, remove this line", |
| 1022 | + "", |
| 1023 | + Applicability::MaybeIncorrect, |
| 1024 | + ) |
| 1025 | + .emit(); |
| 1026 | + }); |
| 1027 | +} |
| 1028 | + |
986 | 1029 | fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) { |
987 | 1030 | tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { |
988 | 1031 | lint.build(&format!( |
989 | | - "the feature `{}` has been stable since {} and no longer requires \ |
990 | | - an attribute to enable", |
991 | | - feature, since |
| 1032 | + "the feature `{feature}` has been stable since {since} and no longer requires an \ |
| 1033 | + attribute to enable", |
992 | 1034 | )) |
993 | 1035 | .emit(); |
994 | 1036 | }); |
|
0 commit comments