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