|
3 | 3 |
|
4 | 4 | use attr::StabilityLevel;
|
5 | 5 | use rustc_attr::{self as attr, ConstStability, Stability, Unstable};
|
6 |
| -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; |
| 6 | +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; |
7 | 7 | use rustc_errors::{struct_span_err, Applicability};
|
8 | 8 | use rustc_hir as hir;
|
9 | 9 | use rustc_hir::def::{DefKind, Res};
|
@@ -952,40 +952,52 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
952 | 952 | remaining_lib_features.remove(&sym::libc);
|
953 | 953 | remaining_lib_features.remove(&sym::test);
|
954 | 954 |
|
| 955 | + // We always collect the lib features declared in the current crate, even if there are |
| 956 | + // no unknown features, because the collection also does feature attribute validation. |
| 957 | + let local_defined_features = tcx.lib_features(()); |
| 958 | + let mut all_lib_features: FxHashMap<_, _> = |
| 959 | + local_defined_features.to_vec().iter().map(|el| *el).collect(); |
955 | 960 | let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone();
|
956 | 961 | for &cnum in tcx.crates(()) {
|
957 | 962 | implications.extend(tcx.stability_implications(cnum));
|
| 963 | + all_lib_features.extend(tcx.defined_lib_features(cnum).iter().map(|el| *el)); |
| 964 | + } |
| 965 | + |
| 966 | + // Check that every feature referenced by an `implied_by` exists (for features defined in the |
| 967 | + // local crate). |
| 968 | + for (implied_by, feature) in tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE) { |
| 969 | + // Only `implied_by` needs to be checked, `feature` is guaranteed to exist. |
| 970 | + if !all_lib_features.contains_key(implied_by) { |
| 971 | + let span = local_defined_features |
| 972 | + .stable |
| 973 | + .get(feature) |
| 974 | + .map(|(_, span)| span) |
| 975 | + .or_else(|| local_defined_features.unstable.get(feature)) |
| 976 | + .expect("feature that implied another does not exist"); |
| 977 | + tcx.sess |
| 978 | + .struct_span_err( |
| 979 | + *span, |
| 980 | + format!("feature `{implied_by}` implying `{feature}` does not exist"), |
| 981 | + ) |
| 982 | + .emit(); |
| 983 | + } |
958 | 984 | }
|
959 | 985 |
|
960 |
| - let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| { |
961 |
| - for &(feature, since) in defined_features { |
| 986 | + if !remaining_lib_features.is_empty() { |
| 987 | + for (feature, since) in all_lib_features.iter() { |
962 | 988 | if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
|
963 | 989 | // Warn if the user has enabled an already-stable lib feature.
|
964 | 990 | if let Some(implies) = implications.get(&feature) {
|
965 |
| - unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since); |
| 991 | + unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since); |
966 | 992 | } else {
|
967 |
| - unnecessary_stable_feature_lint(tcx, *span, feature, since); |
| 993 | + unnecessary_stable_feature_lint(tcx, *span, *feature, *since); |
968 | 994 | }
|
969 | 995 | }
|
970 | 996 | remaining_lib_features.remove(&feature);
|
971 | 997 | if remaining_lib_features.is_empty() {
|
972 | 998 | break;
|
973 | 999 | }
|
974 | 1000 | }
|
975 |
| - }; |
976 |
| - |
977 |
| - // We always collect the lib features declared in the current crate, even if there are |
978 |
| - // no unknown features, because the collection also does feature attribute validation. |
979 |
| - let local_defined_features = tcx.lib_features(()).to_vec(); |
980 |
| - if !remaining_lib_features.is_empty() { |
981 |
| - check_features(&mut remaining_lib_features, &local_defined_features); |
982 |
| - |
983 |
| - for &cnum in tcx.crates(()) { |
984 |
| - if remaining_lib_features.is_empty() { |
985 |
| - break; |
986 |
| - } |
987 |
| - check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum)); |
988 |
| - } |
989 | 1001 | }
|
990 | 1002 |
|
991 | 1003 | for (feature, span) in remaining_lib_features {
|
|
0 commit comments