From 1bfa1d51fd220ee5281176f565581cd9dfeaa380 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 15 Oct 2016 10:28:12 -0700 Subject: [PATCH] introing one-time diagnostics: only emit "lint level defined here" once We introduce a new `one_time_diagnostics` field on `rustc::session::Session` to hold a hashset of diagnostic messages we've set once but don't want to see again (as uniquified by span and message text), "lint level defined here" being the motivating example dealt with here. This is in the matter of #24690. --- src/librustc/lint/context.rs | 3 +-- src/librustc/session/mod.rs | 27 ++++++++++++++++++- src/test/compile-fail/lint-group-style.rs | 2 -- .../lint-unconditional-recursion.rs | 14 +--------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 81d3d440b56..eebf4d32ab2 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -452,8 +452,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, } if let Some(span) = def { - let explanation = "lint level defined here"; - err.span_note(span, &explanation); + sess.diag_span_note_once(&mut err, span, "lint level defined here"); } err diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index d002aba595b..7917964c8f1 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -17,7 +17,7 @@ use middle::dependency_format; use session::search_paths::PathKind; use session::config::DebugInfoLevel; use ty::tls; -use util::nodemap::{NodeMap, FnvHashMap}; +use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; use util::common::duration_to_secs_str; use mir::transform as mir_pass; @@ -75,6 +75,10 @@ pub struct Session { pub working_dir: PathBuf, pub lint_store: RefCell, pub lints: RefCell>>, + /// Set of (span, message) tuples tracking lint (sub)diagnostics that have + /// been set once, but should not be set again, in order to avoid + /// redundantly verbose output (Issue #24690). + pub one_time_diagnostics: RefCell>, pub plugin_llvm_passes: RefCell>, pub mir_passes: RefCell, pub plugin_attributes: RefCell>, @@ -288,6 +292,26 @@ impl Session { pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler { &self.parse_sess.span_diagnostic } + + /// Analogous to calling `.span_note` on the given DiagnosticBuilder, but + /// deduplicates on span and message for this `Session`. + // + // FIXME: if the need arises for one-time diagnostics other than + // `span_note`, we almost certainly want to generalize this "check the + // one-time diagnostics map, then set message if it's not already there" + // code to accomodate all of them + pub fn diag_span_note_once<'a, 'b>(&'a self, + diag_builder: &'b mut DiagnosticBuilder<'a>, + span: Span, message: &str) { + let span_message = (span, message.to_owned()); + let already_noted: bool = self.one_time_diagnostics.borrow() + .contains(&span_message); + if !already_noted { + diag_builder.span_note(span, &message); + self.one_time_diagnostics.borrow_mut().insert(span_message); + } + } + pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap { self.parse_sess.codemap() } @@ -561,6 +585,7 @@ pub fn build_session_(sopts: config::Options, working_dir: env::current_dir().unwrap(), lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), + one_time_diagnostics: RefCell::new(FnvHashSet()), plugin_llvm_passes: RefCell::new(Vec::new()), mir_passes: RefCell::new(mir_pass::Passes::new()), plugin_attributes: RefCell::new(Vec::new()), diff --git a/src/test/compile-fail/lint-group-style.rs b/src/test/compile-fail/lint-group-style.rs index 393e46ab539..a88e0c63ac3 100644 --- a/src/test/compile-fail/lint-group-style.rs +++ b/src/test/compile-fail/lint-group-style.rs @@ -20,7 +20,6 @@ mod test { #[forbid(bad_style)] //~^ NOTE lint level defined here - //~^^ NOTE lint level defined here mod bad { fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name @@ -30,7 +29,6 @@ mod test { mod warn { #![warn(bad_style)] //~^ NOTE lint level defined here - //~| NOTE lint level defined here fn CamelCase() {} //~ WARN function `CamelCase` should have a snake case name diff --git a/src/test/compile-fail/lint-unconditional-recursion.rs b/src/test/compile-fail/lint-unconditional-recursion.rs index 94e189aa47f..bee5a2c45be 100644 --- a/src/test/compile-fail/lint-unconditional-recursion.rs +++ b/src/test/compile-fail/lint-unconditional-recursion.rs @@ -10,19 +10,7 @@ #![deny(unconditional_recursion)] //~^ NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here -//~| NOTE lint level defined here + #![allow(dead_code)] fn foo() { //~ ERROR function cannot return without recurring foo(); //~ NOTE recursive call site