@@ -962,58 +962,113 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
962962    remaining_lib_features. remove ( & sym:: libc) ; 
963963    remaining_lib_features. remove ( & sym:: test) ; 
964964
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 { 
998991            if  let  Some ( since)  = since && let  Some ( span)  = remaining_lib_features. get ( & feature)  { 
999992                // 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)  { 
1001994                    unnecessary_partially_stable_feature_lint ( tcx,  * span,  * feature,  * implies,  * since) ; 
1002995                }  else  { 
1003996                    unnecessary_stable_feature_lint ( tcx,  * span,  * feature,  * since) ; 
1004997                } 
998+ 
1005999            } 
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 ( )  { 
10081009                break ; 
10091010            } 
10101011        } 
10111012    } 
10121013
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+ 
10131052    for  ( feature,  span)  in  remaining_lib_features { 
10141053        struct_span_err ! ( tcx. sess,  span,  E0635 ,  "unknown feature `{}`" ,  feature) . emit ( ) ; 
10151054    } 
10161055
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+ 
10171072    // FIXME(#44232): the `used_features` table no longer exists, so we 
10181073    // don't lint about unused features. We should re-enable this one day! 
10191074} 
0 commit comments