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 @@ fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} 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 @@ fn emit_future_breakage_report(&mut self, diags: Vec<(FutureBreakage, crate::Dia } } + 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 @@ pub fn emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic 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 @@ fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) { 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()) } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index b5506acf735..3f2d312e61b 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -893,6 +893,7 @@ fn inject_dependency_if( 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 { @@ -917,6 +918,7 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) { ) } }; + unused_externs.push(name as &str); self.sess.parse_sess.buffer_lint_with_diagnostic( lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, @@ -929,6 +931,8 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) { diag, ); } + // FIXME: add gating + self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs); } pub fn postprocess(&mut self, krate: &ast::Crate) {