Add runtime check to avoid overwrite arg easily in diag and store and restore snapshot when set subdiag arg

Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
This commit is contained in:
xizheyin
2025-06-22 00:12:13 +08:00
parent 2fcf1776b9
commit d2d17c60bd
22 changed files with 119 additions and 39 deletions

View File

@@ -289,6 +289,9 @@ pub struct DiagInner {
pub suggestions: Suggestions,
pub args: DiagArgMap,
// This is used to store args and restore them after a subdiagnostic is rendered.
pub reserved_args: DiagArgMap,
/// This is not used for highlighting or rendering any error message. Rather, it can be used
/// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
/// `span` if there is one. Otherwise, it is `DUMMY_SP`.
@@ -319,6 +322,7 @@ impl DiagInner {
children: vec![],
suggestions: Suggestions::Enabled(vec![]),
args: Default::default(),
reserved_args: Default::default(),
sort_span: DUMMY_SP,
is_lint: None,
long_ty_path: None,
@@ -390,7 +394,27 @@ impl DiagInner {
}
pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path));
let name = name.into();
let value = arg.into_diag_arg(&mut self.long_ty_path);
// This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg.
debug_assert!(
!self.args.contains_key(&name) || self.args.get(&name) == Some(&value),
"arg {} already exists",
name
);
self.args.insert(name, value);
}
pub fn remove_arg(&mut self, name: &str) {
self.args.swap_remove(name);
}
pub fn store_args(&mut self) {
self.reserved_args = self.args.clone();
}
pub fn restore_args(&mut self) {
self.args = std::mem::take(&mut self.reserved_args);
}
/// Fields used for Hash, and PartialEq trait.
@@ -1423,6 +1447,12 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self.downgrade_to_delayed_bug();
self.emit()
}
pub fn remove_arg(&mut self, name: &str) {
if let Some(diag) = self.diag.as_mut() {
diag.remove_arg(name);
}
}
}
/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.)