Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 29 additions & 42 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::path::PathBuf;
use std::thread::panicking;

use rustc_ast::attr::version::RustcVersion;
use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
use rustc_data_structures::stable_hash::StableHasher;
use rustc_error_messages::{DiagArgMap, DiagArgName, IntoDiagArg};
use rustc_hashes::Hash128;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_macros::{Decodable, Encodable};
use rustc_span::{DUMMY_SP, Span, Spanned, Symbol};
Expand Down Expand Up @@ -305,46 +307,31 @@ impl DiagInner {
}
}

/// Fields used for Hash, and PartialEq trait.
fn keys(
&self,
) -> (
&Level,
&[(DiagMessage, Style)],
&Option<ErrCode>,
&MultiSpan,
&[Subdiag],
&Suggestions,
Vec<(&DiagArgName, &DiagArgValue)>,
&Option<IsLint>,
) {
(
&self.level,
&self.messages,
&self.code,
&self.span,
&self.children,
&self.suggestions,
self.args.iter().collect(),
// omit self.sort_span
&self.is_lint,
// omit self.emitted_at
)
}
}

impl Hash for DiagInner {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.keys().hash(state);
}
}

impl PartialEq for DiagInner {
fn eq(&self, other: &Self) -> bool {
self.keys() == other.keys()
/// Hash used to determine if two diagnostics are the same. Used by
/// `DiagCtxtInner::emitted_diagnostics`. Some fields are ignored for the hash.
pub(crate) fn dedup_hash(&self) -> Hash128 {
// Deconstruct to ensure all fields are considered.
let DiagInner {
level,
messages,
code,
lint_id: _, // ignore
span,
children,
suggestions,
args,
sort_span: _, // ignore
is_lint,
long_ty_path: _, // ignore
emitted_at: _, // ignore
} = self;

let hashed_parts =
(level, messages, code, span, children, suggestions, args.as_slice(), is_lint);

let mut hasher = StableHasher::new();
hashed_parts.hash(&mut hasher);
hasher.finish()
}
}

Expand Down
13 changes: 5 additions & 8 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,10 @@ struct DiagCtxtInner {
emitted_diagnostic_codes: FxIndexSet<ErrCode>,

/// This set contains a hash of every diagnostic that has been emitted by
/// this `DiagCtxt`. These hashes is used to avoid emitting the same error
/// twice.
/// this `DiagCtxt`. These hashes are used to avoid emitting the same error
/// twice. (Because we don't store the diagnostics themselves, two
/// different diagnostics with the same hash value will be considered
/// equivalent. Such collisions should be vanishingly rare...)
emitted_diagnostics: FxHashSet<Hash128>,

/// We only want to emit `recursion_depth_exceeding_limit` once per
Expand Down Expand Up @@ -1301,12 +1303,7 @@ impl DiagCtxtInner {
self.emitted_diagnostic_codes.insert(code);
}

let already_emitted = {
let mut hasher = StableHasher::new();
diagnostic.hash(&mut hasher);
let diagnostic_hash = hasher.finish();
!self.emitted_diagnostics.insert(diagnostic_hash)
};
let already_emitted = !self.emitted_diagnostics.insert(diagnostic.dedup_hash());

let is_error = diagnostic.is_error();
let is_lint = diagnostic.is_lint.is_some();
Expand Down
Loading