@@ -26,7 +26,7 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa
26
26
use rustc_errors:: PResult ;
27
27
use rustc_expand:: base:: ExtCtxt ;
28
28
use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
29
- use rustc_hir:: Crate ;
29
+ use rustc_hir:: { Crate , CRATE_HIR_ID } ;
30
30
use rustc_infer:: traits;
31
31
use rustc_lint:: LintStore ;
32
32
use rustc_mir as mir;
@@ -35,6 +35,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
35
35
use rustc_passes:: { self , hir_stats, layout_test} ;
36
36
use rustc_plugin_impl as plugin;
37
37
use rustc_resolve:: { Resolver , ResolverArenas } ;
38
+ use rustc_span:: symbol:: sym;
38
39
use rustc_span:: symbol:: Symbol ;
39
40
use rustc_span:: FileName ;
40
41
use rustc_typeck as typeck;
@@ -50,6 +51,9 @@ use std::path::PathBuf;
50
51
use std:: rc:: Rc ;
51
52
use std:: { env, fs, iter, mem} ;
52
53
54
+ use log:: debug;
55
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
56
+
53
57
pub fn parse < ' a > ( sess : & ' a Session , input : & Input ) -> PResult < ' a , ast:: Crate > {
54
58
let krate = sess. time ( "parse_crate" , || match input {
55
59
Input :: File ( file) => parse_crate_from_file ( file, & sess. parse_sess ) ,
@@ -733,6 +737,9 @@ pub fn create_global_ctxt<'tcx>(
733
737
callback ( sess, & mut local_providers, & mut extern_providers) ;
734
738
}
735
739
740
+ let extern_prelude = resolver_outputs. extern_prelude . clone ( ) ;
741
+ let used_crates = resolver_outputs. used_crates . clone ( ) ;
742
+
736
743
let gcx = sess. time ( "setup_global_ctxt" , || {
737
744
global_ctxt. init_locking ( || {
738
745
TyCtxt :: create_global_ctxt (
@@ -753,11 +760,60 @@ pub fn create_global_ctxt<'tcx>(
753
760
// Do some initialization of the DepGraph that can only be done with the tcx available.
754
761
ty:: tls:: enter_global ( & gcx, |tcx| {
755
762
tcx. sess . time ( "dep_graph_tcx_init" , || rustc_incremental:: dep_graph_tcx_init ( tcx) ) ;
763
+ check_unused_crates ( tcx, & extern_prelude, & used_crates) ;
756
764
} ) ;
757
765
758
766
QueryContext ( gcx)
759
767
}
760
768
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
+
761
817
/// Runs the resolution, type-checking, region checking and other
762
818
/// miscellaneous analysis passes on the crate.
763
819
fn analysis ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> Result < ( ) > {
0 commit comments