@@ -962,58 +962,113 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
962
962
remaining_lib_features. remove ( & sym:: libc) ;
963
963
remaining_lib_features. remove ( & sym:: test) ;
964
964
965
- // We always collect the lib features declared in the current crate, even if there are
966
- // no unknown features, because the collection also does feature attribute validation.
967
- let local_defined_features = tcx. lib_features ( ( ) ) ;
968
- let mut all_lib_features: FxHashMap < _ , _ > =
969
- local_defined_features. to_vec ( ) . iter ( ) . map ( |el| * el) . collect ( ) ;
970
- let mut implications = tcx. stability_implications ( rustc_hir:: def_id:: LOCAL_CRATE ) . clone ( ) ;
971
- for & cnum in tcx. crates ( ( ) ) {
972
- implications. extend ( tcx. stability_implications ( cnum) ) ;
973
- all_lib_features. extend ( tcx. defined_lib_features ( cnum) . iter ( ) . map ( |el| * el) ) ;
974
- }
975
-
976
- // Check that every feature referenced by an `implied_by` exists (for features defined in the
977
- // local crate).
978
- for ( implied_by, feature) in tcx. stability_implications ( rustc_hir:: def_id:: LOCAL_CRATE ) {
979
- // Only `implied_by` needs to be checked, `feature` is guaranteed to exist.
980
- if !all_lib_features. contains_key ( implied_by) {
981
- let span = local_defined_features
982
- . stable
983
- . get ( feature)
984
- . map ( |( _, span) | span)
985
- . or_else ( || local_defined_features. unstable . get ( feature) )
986
- . expect ( "feature that implied another does not exist" ) ;
987
- tcx. sess
988
- . struct_span_err (
989
- * span,
990
- format ! ( "feature `{implied_by}` implying `{feature}` does not exist" ) ,
991
- )
992
- . emit ( ) ;
993
- }
994
- }
995
-
996
- if !remaining_lib_features. is_empty ( ) {
997
- for ( feature, since) in all_lib_features. iter ( ) {
965
+ /// For each feature in `defined_features`..
966
+ ///
967
+ /// - If it is in `remaining_lib_features` (those features with `#![feature(..)]` attributes in
968
+ /// the current crate), check if it is stable (or partially stable) and thus an unnecessary
969
+ /// attribute.
970
+ /// - If it is in `remaining_implications` (a feature that is referenced by an `implied_by`
971
+ /// from the current crate), then remove it from the remaining implications.
972
+ ///
973
+ /// Once this function has been invoked for every feature (local crate and all extern crates),
974
+ /// then..
975
+ ///
976
+ /// - If features remain in `remaining_lib_features`, then the user has enabled a feature that
977
+ /// does not exist.
978
+ /// - If features remain in `remaining_implications`, the `implied_by` refers to a feature that
979
+ /// does not exist.
980
+ ///
981
+ /// By structuring the code in this way: checking the features defined from each crate one at a
982
+ /// time, less loading from metadata is performed and thus compiler performance is improved.
983
+ fn check_features < ' tcx > (
984
+ tcx : TyCtxt < ' tcx > ,
985
+ remaining_lib_features : & mut FxIndexMap < & Symbol , Span > ,
986
+ remaining_implications : & mut FxHashMap < Symbol , Symbol > ,
987
+ defined_features : & [ ( Symbol , Option < Symbol > ) ] ,
988
+ all_implications : & FxHashMap < Symbol , Symbol > ,
989
+ ) {
990
+ for ( feature, since) in defined_features {
998
991
if let Some ( since) = since && let Some ( span) = remaining_lib_features. get ( & feature) {
999
992
// Warn if the user has enabled an already-stable lib feature.
1000
- if let Some ( implies) = implications . get ( & feature) {
993
+ if let Some ( implies) = all_implications . get ( & feature) {
1001
994
unnecessary_partially_stable_feature_lint ( tcx, * span, * feature, * implies, * since) ;
1002
995
} else {
1003
996
unnecessary_stable_feature_lint ( tcx, * span, * feature, * since) ;
1004
997
}
998
+
1005
999
}
1006
- remaining_lib_features. remove ( & feature) ;
1007
- if remaining_lib_features. is_empty ( ) {
1000
+ remaining_lib_features. remove ( feature) ;
1001
+
1002
+ // `feature` is the feature doing the implying, but `implied_by` is the feature with
1003
+ // the attribute that establishes this relationship. `implied_by` is guaranteed to be a
1004
+ // feature defined in the local crate because `remaining_implications` is only the
1005
+ // implications from this crate.
1006
+ remaining_implications. remove ( feature) ;
1007
+
1008
+ if remaining_lib_features. is_empty ( ) && remaining_implications. is_empty ( ) {
1008
1009
break ;
1009
1010
}
1010
1011
}
1011
1012
}
1012
1013
1014
+ // All local crate implications need to have the feature that implies it confirmed to exist.
1015
+ let mut remaining_implications =
1016
+ tcx. stability_implications ( rustc_hir:: def_id:: LOCAL_CRATE ) . clone ( ) ;
1017
+
1018
+ // We always collect the lib features declared in the current crate, even if there are
1019
+ // no unknown features, because the collection also does feature attribute validation.
1020
+ let local_defined_features = tcx. lib_features ( ( ) ) . to_vec ( ) ;
1021
+ if !remaining_lib_features. is_empty ( ) || !remaining_implications. is_empty ( ) {
1022
+ // Loading the implications of all crates is unavoidable to be able to emit the partial
1023
+ // stabilization diagnostic, but it can be avoided when there are no
1024
+ // `remaining_lib_features`.
1025
+ let mut all_implications = remaining_implications. clone ( ) ;
1026
+ for & cnum in tcx. crates ( ( ) ) {
1027
+ all_implications. extend ( tcx. stability_implications ( cnum) ) ;
1028
+ }
1029
+
1030
+ check_features (
1031
+ tcx,
1032
+ & mut remaining_lib_features,
1033
+ & mut remaining_implications,
1034
+ local_defined_features. as_slice ( ) ,
1035
+ & all_implications,
1036
+ ) ;
1037
+
1038
+ for & cnum in tcx. crates ( ( ) ) {
1039
+ if remaining_lib_features. is_empty ( ) && remaining_implications. is_empty ( ) {
1040
+ break ;
1041
+ }
1042
+ check_features (
1043
+ tcx,
1044
+ & mut remaining_lib_features,
1045
+ & mut remaining_implications,
1046
+ tcx. defined_lib_features ( cnum) . to_vec ( ) . as_slice ( ) ,
1047
+ & all_implications,
1048
+ ) ;
1049
+ }
1050
+ }
1051
+
1013
1052
for ( feature, span) in remaining_lib_features {
1014
1053
struct_span_err ! ( tcx. sess, span, E0635 , "unknown feature `{}`" , feature) . emit ( ) ;
1015
1054
}
1016
1055
1056
+ for ( implied_by, feature) in remaining_implications {
1057
+ let local_defined_features = tcx. lib_features ( ( ) ) ;
1058
+ let span = local_defined_features
1059
+ . stable
1060
+ . get ( & feature)
1061
+ . map ( |( _, span) | span)
1062
+ . or_else ( || local_defined_features. unstable . get ( & feature) )
1063
+ . expect ( "feature that implied another does not exist" ) ;
1064
+ tcx. sess
1065
+ . struct_span_err (
1066
+ * span,
1067
+ format ! ( "feature `{implied_by}` implying `{feature}` does not exist" ) ,
1068
+ )
1069
+ . emit ( ) ;
1070
+ }
1071
+
1017
1072
// FIXME(#44232): the `used_features` table no longer exists, so we
1018
1073
// don't lint about unused features. We should re-enable this one day!
1019
1074
}
0 commit comments