From aef1e35edc11b3e0ecf7f77bc70c197062023476 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 30 Jun 2020 18:58:15 +0200 Subject: Emit unused externs --- compiler/rustc_errors/src/emitter.rs | 3 +++ compiler/rustc_errors/src/json.rs | 19 +++++++++++++++++++ compiler/rustc_errors/src/lib.rs | 8 ++++++++ 3 files changed, 30 insertions(+) (limited to 'compiler/rustc_errors/src') diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 9b6f67166bd..dbb71d52e49 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -195,6 +195,9 @@ pub trait Emitter { fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {} + /// Emit list of unused externs + fn emit_unused_externs(&mut self, _unused_externs: &[&str]) {} + /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { true diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index c27b39a9d62..a1ab98f766e 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -159,6 +159,19 @@ impl Emitter for JsonEmitter { } } + fn emit_unused_externs(&mut self, unused_externs: &[&str]) { + let data = UnusedExterns { unused_extern_names: unused_externs }; + let result = if self.pretty { + writeln!(&mut self.dst, "{}", as_pretty_json(&data)) + } else { + writeln!(&mut self.dst, "{}", as_json(&data)) + } + .and_then(|_| self.dst.flush()); + if let Err(e) = result { + panic!("failed to print unused externs: {:?}", e); + } + } + fn source_map(&self) -> Option<&Lrc> { Some(&self.sm) } @@ -322,6 +335,12 @@ struct FutureIncompatReport { future_incompat_report: Vec, } +#[derive(Encodable)] +struct UnusedExterns<'a, 'b> { + /// List of unused externs by their names. + unused_extern_names: &'a [&'b str], +} + impl Diagnostic { fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { let sugg = diag.suggestions.iter().map(|sugg| Diagnostic { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a0be7442d59..5720e98abc8 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -767,6 +767,10 @@ impl Handler { self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) } + pub fn emit_unused_externs(&self, unused_externs: &[&str]) { + self.inner.borrow_mut().emit_unused_externs(unused_externs) + } + pub fn delay_as_bug(&self, diagnostic: Diagnostic) { self.inner.borrow_mut().delay_as_bug(diagnostic) } @@ -841,6 +845,10 @@ impl HandlerInner { self.emitter.emit_artifact_notification(path, artifact_type); } + fn emit_unused_externs(&mut self, unused_externs: &[&str]) { + self.emitter.emit_unused_externs(unused_externs); + } + fn treat_err_as_bug(&self) -> bool { self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get()) } -- cgit 1.4.1-3-g733a5 From 3a62eb74db63f1b49d5e00c32192498abaf1640f Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 10 Aug 2020 01:57:35 +0200 Subject: Emit the lint level of the unused-crate-dependencies Also, turn off the lint when the unused dependencies json flag is specified so that cargo doesn't have to supress the lint --- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_errors/src/json.rs | 10 ++++++---- compiler/rustc_errors/src/lib.rs | 8 ++++---- compiler/rustc_interface/src/passes.rs | 7 +++++++ compiler/rustc_metadata/src/creader.rs | 36 ++++++++++++++++++++++++++-------- src/librustdoc/doctest.rs | 22 +++++++++++++++++++-- 6 files changed, 66 insertions(+), 19 deletions(-) (limited to 'compiler/rustc_errors/src') diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index dbb71d52e49..2b6dec905f1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -196,7 +196,7 @@ pub trait Emitter { fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {} /// Emit list of unused externs - fn emit_unused_externs(&mut self, _unused_externs: &[&str]) {} + fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {} /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index a1ab98f766e..8511b51e3bf 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -159,8 +159,8 @@ impl Emitter for JsonEmitter { } } - fn emit_unused_externs(&mut self, unused_externs: &[&str]) { - let data = UnusedExterns { unused_extern_names: unused_externs }; + fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) { + let data = UnusedExterns { lint_level, unused_extern_names: unused_externs }; let result = if self.pretty { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) } else { @@ -336,9 +336,11 @@ struct FutureIncompatReport { } #[derive(Encodable)] -struct UnusedExterns<'a, 'b> { +struct UnusedExterns<'a, 'b, 'c> { + /// The severity level of the unused dependencies lint + lint_level: &'a str, /// List of unused externs by their names. - unused_extern_names: &'a [&'b str], + unused_extern_names: &'b [&'c str], } impl Diagnostic { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5720e98abc8..533c32b32c6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -767,8 +767,8 @@ impl Handler { self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) } - pub fn emit_unused_externs(&self, unused_externs: &[&str]) { - self.inner.borrow_mut().emit_unused_externs(unused_externs) + pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) { + self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs) } pub fn delay_as_bug(&self, diagnostic: Diagnostic) { @@ -845,8 +845,8 @@ impl HandlerInner { self.emitter.emit_artifact_notification(path, artifact_type); } - fn emit_unused_externs(&mut self, unused_externs: &[&str]) { - self.emitter.emit_unused_externs(unused_externs); + fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) { + self.emitter.emit_unused_externs(lint_level, unused_externs); } fn treat_err_as_bug(&self) -> bool { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5217066bbef..717f4d5a3ba 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -17,6 +17,7 @@ use rustc_hir::definitions::Definitions; use rustc_hir::Crate; use rustc_index::vec::IndexVec; use rustc_lint::LintStore; +use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::middle; @@ -836,6 +837,12 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { }); sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx)); + + let cstore = tcx + .cstore_as_any() + .downcast_ref::() + .expect("`tcx.cstore` is not a `CStore`"); + cstore.report_unused_deps(tcx); }, { par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 7b34374032c..9e3f121378c 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -46,6 +46,9 @@ pub struct CStore { /// This map is used to verify we get no hash conflicts between /// `StableCrateId` values. stable_crate_ids: FxHashMap, + + /// Unused externs of the crate + unused_externs: Vec, } pub struct CrateLoader<'a> { @@ -190,6 +193,21 @@ impl CStore { crate fn has_global_allocator(&self) -> bool { self.has_global_allocator } + + pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { + let level = tcx + .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID) + .0; + if level != lint::Level::Allow && tcx.sess.opts.json_unused_externs { + let unused_externs = + self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::>(); + let unused_externs = unused_externs.iter().map(String::as_str).collect::>(); + tcx.sess + .parse_sess + .span_diagnostic + .emit_unused_externs(level.as_str(), &unused_externs); + } + } } impl<'a> CrateLoader<'a> { @@ -217,6 +235,7 @@ impl<'a> CrateLoader<'a> { allocator_kind: None, has_global_allocator: false, stable_crate_ids, + unused_externs: Vec::new(), }, used_extern_options: Default::default(), } @@ -893,18 +912,23 @@ impl<'a> CrateLoader<'a> { fn report_unused_deps(&mut self, krate: &ast::Crate) { // Make a point span rather than covering the whole file let span = krate.span.shrink_to_lo(); - let mut unused_externs = Vec::new(); // Complain about anything left over for (name, entry) in self.sess.opts.externs.iter() { if let ExternLocation::FoundInLibrarySearchDirectories = entry.location { // Don't worry about pathless `--extern foo` sysroot references continue; } - if self.used_extern_options.contains(&Symbol::intern(name)) { + let name_interned = Symbol::intern(name); + if self.used_extern_options.contains(&name_interned) { continue; } // Got a real unused --extern + if self.sess.opts.json_unused_externs { + self.cstore.unused_externs.push(name_interned); + continue; + } + let diag = match self.sess.opts.extern_dep_specs.get(name) { Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()), None => { @@ -918,7 +942,6 @@ impl<'a> CrateLoader<'a> { ) } }; - unused_externs.push(name as &str); self.sess.parse_sess.buffer_lint_with_diagnostic( lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, @@ -931,9 +954,6 @@ impl<'a> CrateLoader<'a> { diag, ); } - if self.sess.opts.json_unused_externs { - self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs); - } } pub fn postprocess(&mut self, krate: &ast::Crate) { @@ -941,9 +961,9 @@ impl<'a> CrateLoader<'a> { self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); - info!("{:?}", CrateDump(&self.cstore)); - self.report_unused_deps(krate); + + info!("{:?}", CrateDump(&self.cstore)); } pub fn process_extern_crate( diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 50cdf46ce4f..116b3aad61e 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -188,8 +188,23 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { .map(|v| (*v).clone()) .collect::>(); unused_extern_names.sort(); - let unused_extern_json = - serde_json::to_string(&UnusedExterns { unused_extern_names }).unwrap(); + // Take the most severe lint level + let lint_level = unused_extern_reports + .iter() + .map(|uexts| uexts.lint_level.as_str()) + .max_by_key(|v| match *v { + "warn" => 1, + "deny" => 2, + "forbid" => 3, + // The allow lint level is not expected, + // as if allow is specified, no message + // is to be emitted. + v => unreachable!("Invalid lint level '{}'", v), + }) + .unwrap_or("warn") + .to_string(); + let uext = UnusedExterns { lint_level, unused_extern_names }; + let unused_extern_json = serde_json::to_string(&uext).unwrap(); eprintln!("{}", unused_extern_json); } } @@ -265,6 +280,8 @@ impl DirState { #[derive(serde::Serialize, serde::Deserialize)] struct UnusedExterns { + /// Lint level of the unused_crate_dependencies lint + lint_level: String, /// List of unused externs by their names. unused_extern_names: Vec, } @@ -317,6 +334,7 @@ fn run_test( compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-Z").arg("unstable-options"); + compiler.arg("-W").arg("unused_crate_dependencies"); } for lib_str in &options.lib_strs { compiler.arg("-L").arg(&lib_str); -- cgit 1.4.1-3-g733a5 From d018ef180d9bc4e852457fd83fda0bec8452baf6 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 2 Mar 2021 03:07:13 +0100 Subject: Add notes to keep the UnusedExterns structs synced up --- compiler/rustc_errors/src/json.rs | 4 ++++ src/librustdoc/doctest.rs | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'compiler/rustc_errors/src') diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 8511b51e3bf..3753ca580e7 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -335,6 +335,10 @@ struct FutureIncompatReport { future_incompat_report: Vec, } +// NOTE: Keep this in sync with the equivalent structs in rustdoc's +// doctest component (as well as cargo). +// We could unify this struct the one in rustdoc but they have different +// ownership semantics, so doing so would create wasteful allocations. #[derive(Encodable)] struct UnusedExterns<'a, 'b, 'c> { /// The severity level of the unused dependencies lint diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 116b3aad61e..f7a6ccfc7d1 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -278,6 +278,10 @@ impl DirState { } } +// NOTE: Keep this in sync with the equivalent structs in rustc +// and cargo. +// We could unify this struct the one in rustc but they have different +// ownership semantics, so doing so would create wasteful allocations. #[derive(serde::Serialize, serde::Deserialize)] struct UnusedExterns { /// Lint level of the unused_crate_dependencies lint -- cgit 1.4.1-3-g733a5