|
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