@@ -26,7 +26,7 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa
2626use rustc_errors:: PResult ;
2727use rustc_expand:: base:: ExtCtxt ;
2828use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
29- use rustc_hir:: Crate ;
29+ use rustc_hir:: { Crate , CRATE_HIR_ID } ;
3030use rustc_infer:: traits;
3131use rustc_lint:: LintStore ;
3232use rustc_mir as mir;
@@ -35,6 +35,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
3535use rustc_passes:: { self , hir_stats, layout_test} ;
3636use rustc_plugin_impl as plugin;
3737use rustc_resolve:: { Resolver , ResolverArenas } ;
38+ use rustc_span:: symbol:: sym;
3839use rustc_span:: symbol:: Symbol ;
3940use rustc_span:: FileName ;
4041use rustc_typeck as typeck;
@@ -50,6 +51,9 @@ use std::path::PathBuf;
5051use std:: rc:: Rc ;
5152use std:: { env, fs, iter, mem} ;
5253
54+ use log:: debug;
55+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
56+
5357pub fn parse < ' a > ( sess : & ' a Session , input : & Input ) -> PResult < ' a , ast:: Crate > {
5458 let krate = sess. time ( "parse_crate" , || match input {
5559 Input :: File ( file) => parse_crate_from_file ( file, & sess. parse_sess ) ,
@@ -733,6 +737,9 @@ pub fn create_global_ctxt<'tcx>(
733737 callback ( sess, & mut local_providers, & mut extern_providers) ;
734738 }
735739
740+ let extern_prelude = resolver_outputs. extern_prelude . clone ( ) ;
741+ let used_crates = resolver_outputs. used_crates . clone ( ) ;
742+
736743 let gcx = sess. time ( "setup_global_ctxt" , || {
737744 global_ctxt. init_locking ( || {
738745 TyCtxt :: create_global_ctxt (
@@ -753,11 +760,60 @@ pub fn create_global_ctxt<'tcx>(
753760 // Do some initialization of the DepGraph that can only be done with the tcx available.
754761 ty:: tls:: enter_global ( & gcx, |tcx| {
755762 tcx. sess . time ( "dep_graph_tcx_init" , || rustc_incremental:: dep_graph_tcx_init ( tcx) ) ;
763+ check_unused_crates ( tcx, & extern_prelude, & used_crates) ;
756764 } ) ;
757765
758766 QueryContext ( gcx)
759767}
760768
769+ fn check_unused_crates (
770+ tcx : TyCtxt < ' _ > ,
771+ extern_prelude : & FxHashMap < Symbol , bool > ,
772+ used_crates : & FxHashSet < Symbol > ,
773+ ) {
774+ for ( krate, introduced_by_item) in extern_prelude {
775+ let krate = * krate;
776+ if * introduced_by_item {
777+ debug ! ( "check_unused_crate: crate {:?} added by `extern crate`, skipping" , krate) ;
778+ continue ;
779+ }
780+ if used_crates. contains ( & krate) {
781+ debug ! ( "check_unused_crate: crate {:?} was used, skipping" , krate) ;
782+ continue ;
783+ }
784+
785+ // HACK: These should not be hardcoded. However, libstd needs
786+ // both of them mentioned in its Cargo.tonl, and trying to
787+ // add 'use' or 'extern crate' statements for both crates
788+ // causes an error.
789+ //
790+ // If either of these crates is unused, we will never have loaded
791+ // their metadata (otherwise, they would be used). This means that we have
792+ // no way of checking the `panic_runtime` field in the metadata, and must
793+ // instead rely on the crate name itself.
794+ if krate. as_str ( ) == "panic_abort" || krate. as_str ( ) == "panic_unwind" {
795+ debug ! ( "check_unused_crate: skipping panic runtime crate {:?}" , krate) ;
796+ continue ;
797+ }
798+
799+ if krate == sym:: core || krate == sym:: std {
800+ debug ! ( "check_unused_crate: skipping builtin crate {:?}" , krate) ;
801+ continue ;
802+ }
803+
804+ if tcx. sess . rust_2018 ( ) && krate == sym:: meta {
805+ debug ! ( "check_unused_crate: skipping `meta` crate" ) ;
806+ continue ;
807+ }
808+
809+ tcx. struct_lint_node ( lint:: builtin:: UNUSED_EXTERN_OPTIONS , CRATE_HIR_ID , |lint| {
810+ lint. build ( & format ! ( "crate `{}` is unused in crate `{}`" , krate, tcx. crate_name) )
811+ . help ( & format ! ( "try removing `{}` from your `Cargo.toml`" , krate) )
812+ . emit ( ) ;
813+ } ) ;
814+ }
815+ }
816+
761817/// Runs the resolution, type-checking, region checking and other
762818/// miscellaneous analysis passes on the crate.
763819fn analysis ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> Result < ( ) > {
0 commit comments