1
Fork 0

Factor decorate closure out into a method

This commit is contained in:
Oli Scherer 2022-11-22 12:00:07 +00:00
parent 98dc76a374
commit dec05e9c73

View file

@ -86,6 +86,59 @@ impl<'tcx> ConstEvalErr<'tcx> {
self.report_decorated(tcx, message, |_| {}) self.report_decorated(tcx, message, |_| {})
} }
#[instrument(level = "trace", skip(self, decorate))]
pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) {
trace!("reporting const eval failure at {:?}", self.span);
// Add some more context for select error types.
match self.error {
InterpError::Unsupported(
UnsupportedOpInfo::ReadPointerAsBytes
| UnsupportedOpInfo::PartialPointerOverwrite(_)
| UnsupportedOpInfo::PartialPointerCopy(_),
) => {
err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
}
_ => {}
}
// Add spans for the stacktrace. Don't print a single-line backtrace though.
if self.stacktrace.len() > 1 {
// Helper closure to print duplicated lines.
let mut flush_last_line = |last_frame, times| {
if let Some((line, span)) = last_frame {
err.span_note(span, &line);
// Don't print [... additional calls ...] if the number of lines is small
if times < 3 {
for _ in 0..times {
err.span_note(span, &line);
}
} else {
err.span_note(
span,
format!("[... {} additional calls {} ...]", times, &line),
);
}
}
};
let mut last_frame = None;
let mut times = 0;
for frame_info in &self.stacktrace {
let frame = (frame_info.to_string(), frame_info.span);
if last_frame.as_ref() == Some(&frame) {
times += 1;
} else {
flush_last_line(last_frame, times);
last_frame = Some(frame);
times = 0;
}
}
flush_last_line(last_frame, times);
}
// Let the caller attach any additional information it wants.
decorate(err);
}
/// Create a diagnostic for this const eval error. /// Create a diagnostic for this const eval error.
/// ///
/// Sets the message passed in via `message` and adds span labels with detailed error /// Sets the message passed in via `message` and adds span labels with detailed error
@ -101,88 +154,30 @@ impl<'tcx> ConstEvalErr<'tcx> {
message: &str, message: &str,
decorate: impl FnOnce(&mut Diagnostic), decorate: impl FnOnce(&mut Diagnostic),
) -> ErrorHandled { ) -> ErrorHandled {
let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
trace!("reporting const eval failure at {:?}", self.span);
if let Some(span_msg) = span_msg {
err.span_label(self.span, span_msg);
}
// Add some more context for select error types.
match self.error {
InterpError::Unsupported(
UnsupportedOpInfo::ReadPointerAsBytes
| UnsupportedOpInfo::PartialPointerOverwrite(_)
| UnsupportedOpInfo::PartialPointerCopy(_),
) => {
err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
}
_ => {}
}
// Add spans for the stacktrace. Don't print a single-line backtrace though.
if self.stacktrace.len() > 1 {
// Helper closure to print duplicated lines.
let mut flush_last_line = |last_frame, times| {
if let Some((line, span)) = last_frame {
err.span_note(span, &line);
// Don't print [... additional calls ...] if the number of lines is small
if times < 3 {
for _ in 0..times {
err.span_note(span, &line);
}
} else {
err.span_note(
span,
format!("[... {} additional calls {} ...]", times, &line),
);
}
}
};
let mut last_frame = None;
let mut times = 0;
for frame_info in &self.stacktrace {
let frame = (frame_info.to_string(), frame_info.span);
if last_frame.as_ref() == Some(&frame) {
times += 1;
} else {
flush_last_line(last_frame, times);
last_frame = Some(frame);
times = 0;
}
}
flush_last_line(last_frame, times);
}
// Let the caller attach any additional information it wants.
decorate(err);
};
debug!("self.error: {:?}", self.error); debug!("self.error: {:?}", self.error);
// Special handling for certain errors // Special handling for certain errors
match &self.error { match &self.error {
// Don't emit a new diagnostic for these errors // Don't emit a new diagnostic for these errors
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
return ErrorHandled::TooGeneric; ErrorHandled::TooGeneric
}
err_inval!(AlreadyReported(error_reported)) => {
return ErrorHandled::Reported(*error_reported);
} }
err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported),
err_inval!(Layout(LayoutError::SizeOverflow(_))) => { err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
// We must *always* hard error on these, even if the caller wants just a lint. // We must *always* hard error on these, even if the caller wants just a lint.
// The `message` makes little sense here, this is a more serious error than the // The `message` makes little sense here, this is a more serious error than the
// caller thinks anyway. // caller thinks anyway.
// See <https://github.com/rust-lang/rust/pull/63152>. // See <https://github.com/rust-lang/rust/pull/63152>.
let mut err = struct_error(tcx, &self.error.to_string()); let mut err = struct_error(tcx, &self.error.to_string());
finish(&mut err, None); self.decorate(&mut err, decorate);
return ErrorHandled::Reported(err.emit()); ErrorHandled::Reported(err.emit())
} }
_ => {} _ => {
}; // Report as hard error.
let mut err = struct_error(tcx, message);
let err_msg = self.error.to_string(); err.span_label(self.span, self.error.to_string());
self.decorate(&mut err, decorate);
// Report as hard error. ErrorHandled::Reported(err.emit())
let mut err = struct_error(tcx, message); }
finish(&mut err, Some(err_msg)); }
ErrorHandled::Reported(err.emit())
} }
} }