Skip to content

Commit

Permalink
Add allow-by-default lint UNUSED_EXTERN_OPTIONS
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Aaron1011 committed Mar 12, 2020
1 parent c20d7ee commit 5fa5b9d
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 5 deletions.
5 changes: 4 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use rustc_ast::ast::{self, Ident, Name};
use rustc_ast::node_id::{NodeId, NodeMap, NodeSet};
use rustc_attr as attr;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator};
Expand Down Expand Up @@ -136,6 +136,9 @@ pub struct ResolverOutputs {
/// Extern prelude entries. The value is `true` if the entry was introduced
/// via `extern crate` item and not `--extern` option or compiler built-in.
pub extern_prelude: FxHashMap<Name, bool>,
/// All crates that ended up getting loaded.
/// Used to determine which `--extern` entries are unused
pub used_crates: FxHashSet<Symbol>,
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
Expand Down
58 changes: 57 additions & 1 deletion src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa
use rustc_errors::PResult;
use rustc_expand::base::ExtCtxt;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_hir::Crate;
use rustc_hir::{Crate, CRATE_HIR_ID};
use rustc_infer::traits;
use rustc_lint::LintStore;
use rustc_mir as mir;
Expand All @@ -35,6 +35,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
use rustc_passes::{self, hir_stats, layout_test};
use rustc_plugin_impl as plugin;
use rustc_resolve::{Resolver, ResolverArenas};
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;
use rustc_span::FileName;
use rustc_typeck as typeck;
Expand All @@ -50,6 +51,9 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::{env, fs, iter, mem};

use log::debug;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};

pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
let krate = sess.time("parse_crate", || match input {
Input::File(file) => parse_crate_from_file(file, &sess.parse_sess),
Expand Down Expand Up @@ -733,6 +737,9 @@ pub fn create_global_ctxt<'tcx>(
callback(sess, &mut local_providers, &mut extern_providers);
}

let extern_prelude = resolver_outputs.extern_prelude.clone();
let used_crates = resolver_outputs.used_crates.clone();

let gcx = sess.time("setup_global_ctxt", || {
global_ctxt.init_locking(|| {
TyCtxt::create_global_ctxt(
Expand All @@ -753,11 +760,60 @@ pub fn create_global_ctxt<'tcx>(
// Do some initialization of the DepGraph that can only be done with the tcx available.
ty::tls::enter_global(&gcx, |tcx| {
tcx.sess.time("dep_graph_tcx_init", || rustc_incremental::dep_graph_tcx_init(tcx));
check_unused_crates(tcx, &extern_prelude, &used_crates);
});

QueryContext(gcx)
}

fn check_unused_crates(
tcx: TyCtxt<'_>,
extern_prelude: &FxHashMap<Symbol, bool>,
used_crates: &FxHashSet<Symbol>,
) {
for (krate, introduced_by_item) in extern_prelude {
let krate = *krate;
if *introduced_by_item {
debug!("check_unused_crate: crate {:?} added by `extern crate`, skipping", krate);
continue;
}
if used_crates.contains(&krate) {
debug!("check_unused_crate: crate {:?} was used, skipping", krate);
continue;
}

// HACK: These should not be hardcoded. However, libstd needs
// both of them mentioned in its Cargo.tonl, and trying to
// add 'use' or 'extern crate' statements for both crates
// causes an error.
//
// If either of these crates is unused, we will never have loaded
// their metadata (otherwise, they would be used). This means that we have
// no way of checking the `panic_runtime` field in the metadata, and must
// instead rely on the crate name itself.
if krate.as_str() == "panic_abort" || krate.as_str() == "panic_unwind" {
debug!("check_unused_crate: skipping panic runtime crate {:?}", krate);
continue;
}

if krate == sym::core || krate == sym::std {
debug!("check_unused_crate: skipping builtin crate {:?}", krate);
continue;
}

if tcx.sess.rust_2018() && krate == sym::meta {
debug!("check_unused_crate: skipping `meta` crate");
continue;
}

tcx.struct_lint_node(lint::builtin::UNUSED_EXTERN_OPTIONS, CRATE_HIR_ID, |lint| {
lint.build(&format!("crate `{}` is unused in crate `{}`", krate, tcx.crate_name))
.help(&format!("try removing `{}` from your `Cargo.toml`", krate))
.emit();
});
}
}

/// Runs the resolution, type-checking, region checking and other
/// miscellaneous analysis passes on the crate.
fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};

use log::{debug, info, log_enabled};
use proc_macro::bridge::client::ProcMacro;
use rustc_data_structures::fx::FxHashSet;
use std::path::Path;
use std::{cmp, fs};

Expand All @@ -47,6 +48,7 @@ pub struct CrateLoader<'a> {
local_crate_name: Symbol,
// Mutable output.
cstore: CStore,
loaded_crates: Option<FxHashSet<Symbol>>,
}

pub enum LoadedMacro {
Expand Down Expand Up @@ -197,6 +199,7 @@ impl<'a> CrateLoader<'a> {
allocator_kind: None,
has_global_allocator: false,
},
loaded_crates: Some(Default::default()),
}
}

Expand Down Expand Up @@ -495,6 +498,7 @@ impl<'a> CrateLoader<'a> {
Ok(cnum)
}
(LoadResult::Loaded(library), host_library) => {
self.loaded_crates.as_mut().unwrap().insert(name);
Ok(self.register_crate(host_library, root, span, library, dep_kind, name))
}
_ => panic!(),
Expand Down Expand Up @@ -830,14 +834,15 @@ impl<'a> CrateLoader<'a> {
});
}

pub fn postprocess(&mut self, krate: &ast::Crate) {
pub fn postprocess(&mut self, krate: &ast::Crate) -> FxHashSet<Symbol> {
self.inject_profiler_runtime();
self.inject_allocator_crate(krate);
self.inject_panic_runtime(krate);

if log_enabled!(log::Level::Info) {
dump_crates(&self.cstore);
}
self.loaded_crates.take().unwrap()
}

pub fn process_extern_crate(
Expand Down
9 changes: 7 additions & 2 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use rustc_session::Session;
use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{Span, Symbol, DUMMY_SP};

use log::debug;
use std::cell::{Cell, RefCell};
Expand Down Expand Up @@ -962,6 +962,8 @@ pub struct Resolver<'a> {
lint_buffer: LintBuffer,

next_node_id: NodeId,

used_crates: FxHashSet<Symbol>,
}

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

Expand Down Expand Up @@ -1275,6 +1278,7 @@ impl<'a> Resolver<'a> {
.iter()
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
.collect(),
used_crates: self.used_crates,
}
}

Expand All @@ -1293,6 +1297,7 @@ impl<'a> Resolver<'a> {
.iter()
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
.collect(),
used_crates: self.used_crates.clone(),
}
}

Expand Down Expand Up @@ -1343,7 +1348,7 @@ impl<'a> Resolver<'a> {

self.check_unused(krate);
self.report_errors(krate);
self.crate_loader.postprocess(krate);
self.used_crates = self.crate_loader.postprocess(krate);
}

fn new_module(
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_session/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ declare_lint! {
"extern crates that are never used"
}

declare_lint! {
pub UNUSED_EXTERN_OPTIONS,
Allow,
"extern path crates that are never used"
}

declare_lint! {
pub UNUSED_QUALIFICATIONS,
Allow,
Expand Down Expand Up @@ -505,6 +511,7 @@ declare_lint_pass! {
UNCONDITIONAL_PANIC,
UNUSED_IMPORTS,
UNUSED_EXTERN_CRATES,
UNUSED_EXTERN_OPTIONS,
UNUSED_QUALIFICATIONS,
UNKNOWN_LINTS,
UNUSED_VARIABLES,
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/lint/auxiliary/unused_crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Deliberately empty
5 changes: 5 additions & 0 deletions src/test/ui/lint/unused_extern_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// aux-crate:unused_crate=unused_crate.rs

#![deny(unused_extern_options)]

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/lint/unused_extern_options.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: crate `unused_crate` is unused in crate `unused_extern_options`
|
note: the lint level is defined here
--> $DIR/unused_extern_options.rs:3:9
|
LL | #![deny(unused_extern_options)]
| ^^^^^^^^^^^^^^^^^^^^^
= help: try removing `unused_crate` from your `Cargo.toml`

error: aborting due to previous error

0 comments on commit 5fa5b9d

Please sign in to comment.