Skip to content

Commit 5fa5b9d

Browse files
committed
Add allow-by-default lint UNUSED_EXTERN_OPTIONS
This lint fires for any unused crates in the Rust 2018 extern prelude (e.g. passed in via `--extern`) For now, it is allow-by-default to prevent false positives in multi-target crate. See rust-lang#69203 (comment) for more details, and rust-lang/cargo#1982 for the tracking issue.
1 parent c20d7ee commit 5fa5b9d

File tree

8 files changed

+98
-5
lines changed

8 files changed

+98
-5
lines changed

src/librustc/ty/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use rustc_ast::ast::{self, Ident, Name};
3030
use rustc_ast::node_id::{NodeId, NodeMap, NodeSet};
3131
use rustc_attr as attr;
3232
use rustc_data_structures::captures::Captures;
33-
use rustc_data_structures::fx::FxHashMap;
3433
use rustc_data_structures::fx::FxIndexMap;
34+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
3535
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
3636
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
3737
use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator};
@@ -136,6 +136,9 @@ pub struct ResolverOutputs {
136136
/// Extern prelude entries. The value is `true` if the entry was introduced
137137
/// via `extern crate` item and not `--extern` option or compiler built-in.
138138
pub extern_prelude: FxHashMap<Name, bool>,
139+
/// All crates that ended up getting loaded.
140+
/// Used to determine which `--extern` entries are unused
141+
pub used_crates: FxHashSet<Symbol>,
139142
}
140143

141144
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]

src/librustc_interface/passes.rs

+57-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa
2626
use rustc_errors::PResult;
2727
use rustc_expand::base::ExtCtxt;
2828
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
29-
use rustc_hir::Crate;
29+
use rustc_hir::{Crate, CRATE_HIR_ID};
3030
use rustc_infer::traits;
3131
use rustc_lint::LintStore;
3232
use rustc_mir as mir;
@@ -35,6 +35,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
3535
use rustc_passes::{self, hir_stats, layout_test};
3636
use rustc_plugin_impl as plugin;
3737
use rustc_resolve::{Resolver, ResolverArenas};
38+
use rustc_span::symbol::sym;
3839
use rustc_span::symbol::Symbol;
3940
use rustc_span::FileName;
4041
use rustc_typeck as typeck;
@@ -50,6 +51,9 @@ use std::path::PathBuf;
5051
use std::rc::Rc;
5152
use std::{env, fs, iter, mem};
5253

54+
use log::debug;
55+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
56+
5357
pub 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.
763819
fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {

src/librustc_metadata/creader.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
2626

2727
use log::{debug, info, log_enabled};
2828
use proc_macro::bridge::client::ProcMacro;
29+
use rustc_data_structures::fx::FxHashSet;
2930
use std::path::Path;
3031
use std::{cmp, fs};
3132

@@ -47,6 +48,7 @@ pub struct CrateLoader<'a> {
4748
local_crate_name: Symbol,
4849
// Mutable output.
4950
cstore: CStore,
51+
loaded_crates: Option<FxHashSet<Symbol>>,
5052
}
5153

5254
pub enum LoadedMacro {
@@ -197,6 +199,7 @@ impl<'a> CrateLoader<'a> {
197199
allocator_kind: None,
198200
has_global_allocator: false,
199201
},
202+
loaded_crates: Some(Default::default()),
200203
}
201204
}
202205

@@ -495,6 +498,7 @@ impl<'a> CrateLoader<'a> {
495498
Ok(cnum)
496499
}
497500
(LoadResult::Loaded(library), host_library) => {
501+
self.loaded_crates.as_mut().unwrap().insert(name);
498502
Ok(self.register_crate(host_library, root, span, library, dep_kind, name))
499503
}
500504
_ => panic!(),
@@ -830,14 +834,15 @@ impl<'a> CrateLoader<'a> {
830834
});
831835
}
832836

833-
pub fn postprocess(&mut self, krate: &ast::Crate) {
837+
pub fn postprocess(&mut self, krate: &ast::Crate) -> FxHashSet<Symbol> {
834838
self.inject_profiler_runtime();
835839
self.inject_allocator_crate(krate);
836840
self.inject_panic_runtime(krate);
837841

838842
if log_enabled!(log::Level::Info) {
839843
dump_crates(&self.cstore);
840844
}
845+
self.loaded_crates.take().unwrap()
841846
}
842847

843848
pub fn process_extern_crate(

src/librustc_resolve/lib.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use rustc_session::Session;
4747
use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
4848
use rustc_span::source_map::Spanned;
4949
use rustc_span::symbol::{kw, sym};
50-
use rustc_span::{Span, DUMMY_SP};
50+
use rustc_span::{Span, Symbol, DUMMY_SP};
5151

5252
use log::debug;
5353
use std::cell::{Cell, RefCell};
@@ -962,6 +962,8 @@ pub struct Resolver<'a> {
962962
lint_buffer: LintBuffer,
963963

964964
next_node_id: NodeId,
965+
966+
used_crates: FxHashSet<Symbol>,
965967
}
966968

967969
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1239,6 +1241,7 @@ impl<'a> Resolver<'a> {
12391241
variant_vis: Default::default(),
12401242
lint_buffer: LintBuffer::default(),
12411243
next_node_id: NodeId::from_u32(1),
1244+
used_crates: Default::default(),
12421245
}
12431246
}
12441247

@@ -1275,6 +1278,7 @@ impl<'a> Resolver<'a> {
12751278
.iter()
12761279
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
12771280
.collect(),
1281+
used_crates: self.used_crates,
12781282
}
12791283
}
12801284

@@ -1293,6 +1297,7 @@ impl<'a> Resolver<'a> {
12931297
.iter()
12941298
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
12951299
.collect(),
1300+
used_crates: self.used_crates.clone(),
12961301
}
12971302
}
12981303

@@ -1343,7 +1348,7 @@ impl<'a> Resolver<'a> {
13431348

13441349
self.check_unused(krate);
13451350
self.report_errors(krate);
1346-
self.crate_loader.postprocess(krate);
1351+
self.used_crates = self.crate_loader.postprocess(krate);
13471352
}
13481353

13491354
fn new_module(

src/librustc_session/lint/builtin.rs

+7
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ declare_lint! {
7171
"extern crates that are never used"
7272
}
7373

74+
declare_lint! {
75+
pub UNUSED_EXTERN_OPTIONS,
76+
Allow,
77+
"extern path crates that are never used"
78+
}
79+
7480
declare_lint! {
7581
pub UNUSED_QUALIFICATIONS,
7682
Allow,
@@ -505,6 +511,7 @@ declare_lint_pass! {
505511
UNCONDITIONAL_PANIC,
506512
UNUSED_IMPORTS,
507513
UNUSED_EXTERN_CRATES,
514+
UNUSED_EXTERN_OPTIONS,
508515
UNUSED_QUALIFICATIONS,
509516
UNKNOWN_LINTS,
510517
UNUSED_VARIABLES,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Deliberately empty
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// aux-crate:unused_crate=unused_crate.rs
2+
3+
#![deny(unused_extern_options)]
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: crate `unused_crate` is unused in crate `unused_extern_options`
2+
|
3+
note: the lint level is defined here
4+
--> $DIR/unused_extern_options.rs:3:9
5+
|
6+
LL | #![deny(unused_extern_options)]
7+
| ^^^^^^^^^^^^^^^^^^^^^
8+
= help: try removing `unused_crate` from your `Cargo.toml`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)