Auto merge of #111677 - fee1-dead-contrib:rustc_const_eval-translatable, r=oli-obk,RalfJung

Use translatable diagnostics in `rustc_const_eval`

This PR:

* adds a `no_span` parameter to `note` / `help` attributes when using `Subdiagnostic` to allow adding notes/helps without using a span
* has minor tweaks and changes to error messages
This commit is contained in:
bors 2023-06-02 05:11:49 +00:00
commit 33c3d10128
93 changed files with 2385 additions and 1128 deletions

View file

@ -2,7 +2,7 @@ error: this operation will panic at runtime
--> $DIR/modulo_one.rs:11:5
|
LL | i32::MIN % (-1); // also caught by rustc
| ^^^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
| ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
|
= note: `#[deny(unconditional_panic)]` on by default
@ -10,13 +10,13 @@ error: this operation will panic at runtime
--> $DIR/modulo_one.rs:21:5
|
LL | INT_MIN % NEG_ONE; // also caught by rustc
| ^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
| ^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
error: this operation will panic at runtime
--> $DIR/modulo_one.rs:22:5
|
LL | INT_MIN % STATIC_NEG_ONE; // ONLY caught by rustc
| ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
| ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
error: any number modulo 1 will be 0
--> $DIR/modulo_one.rs:8:5

View file

@ -3,6 +3,8 @@ use std::num::NonZeroU64;
use log::trace;
use rustc_const_eval::ReportErrorExt;
use rustc_errors::DiagnosticMessage;
use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
use rustc_target::abi::{Align, Size};
@ -83,7 +85,21 @@ impl fmt::Display for TerminationInfo {
}
}
impl MachineStopType for TerminationInfo {}
impl fmt::Debug for TerminationInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
impl MachineStopType for TerminationInfo {
fn diagnostic_message(&self) -> DiagnosticMessage {
self.to_string().into()
}
fn add_args(
self: Box<Self>,
_: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>),
) {}
}
/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
@ -302,8 +318,32 @@ pub fn report_error<'tcx, 'mir>(
let stacktrace = ecx.generate_stacktrace();
let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
e.print_backtrace();
msg.insert(0, e.to_string());
let (e, backtrace) = e.into_parts();
backtrace.print_backtrace();
// We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes
// the `InterpError`, we extract the variables it before that.
let extra = match e {
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
Some((alloc_id, access))
}
_ => None
};
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
// label and arguments from the InterpError.
let e = {
let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
let mut diag = ecx.tcx.sess.struct_allow("");
let msg = e.diagnostic_message();
e.add_args(handler, &mut diag);
let s = handler.eagerly_translate_to_string(msg, diag.args());
diag.cancel();
s
};
msg.insert(0, e);
report_msg(
DiagLevel::Error,
if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() },
@ -332,15 +372,12 @@ pub fn report_error<'tcx, 'mir>(
}
// Extra output to help debug specific issues.
match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
eprintln!(
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
range = access.uninit,
);
eprintln!("{:?}", ecx.dump_alloc(*alloc_id));
}
_ => {}
if let Some((alloc_id, access)) = extra {
eprintln!(
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
range = access.uninit,
);
eprintln!("{:?}", ecx.dump_alloc(alloc_id));
}
None
@ -438,12 +475,15 @@ pub fn report_msg<'tcx>(
// Add visual separator before backtrace.
err.note(if extra_span { "BACKTRACE (of the first span):" } else { "BACKTRACE:" });
}
let (mut err, handler) = err.into_diagnostic().unwrap();
// Add backtrace
for (idx, frame_info) in stacktrace.iter().enumerate() {
let is_local = machine.is_local(frame_info);
// No span for non-local frames and the first frame (which is the error site).
if is_local && idx > 0 {
err.span_note(frame_info.span, frame_info.to_string());
err.eager_subdiagnostic(handler, frame_info.as_note(machine.tcx));
} else {
let sm = sess.source_map();
let span = sm.span_to_embeddable_string(frame_info.span);
@ -451,7 +491,7 @@ pub fn report_msg<'tcx>(
}
}
err.emit();
handler.emit_diagnostic(&mut err);
}
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {

View file

@ -422,8 +422,9 @@ pub fn eval_entry<'tcx>(
let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config) {
Ok(v) => v,
Err(err) => {
err.print_backtrace();
panic!("Miri initialization error: {}", err.kind())
let (kind, backtrace) = err.into_parts();
backtrace.print_backtrace();
panic!("Miri initialization error: {kind:?}")
}
};

View file

@ -164,9 +164,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// We don't give a span -- this isn't actually used directly by the program anyway.
let const_val = this
.eval_global(cid, None)
.unwrap_or_else(|err| panic!("failed to evaluate required Rust item: {path:?}\n{err}"));
.unwrap_or_else(|err| panic!("failed to evaluate required Rust item: {path:?}\n{err:?}"));
this.read_scalar(&const_val.into())
.unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err}"))
.unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}"))
}
/// Helper function to get a `libc` constant as a `Scalar`.

View file

@ -43,6 +43,7 @@
extern crate rustc_apfloat;
extern crate rustc_ast;
extern crate rustc_errors;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_const_eval;

View file

@ -10,6 +10,6 @@ fn main() {
unsafe {
let a = data.as_mut_ptr();
let b = a.wrapping_offset(1) as *mut _;
copy_nonoverlapping(a, b, 2); //~ ERROR: copy_nonoverlapping called on overlapping ranges
copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
}
}

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: copy_nonoverlapping called on overlapping ranges
error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
--> $DIR/copy_overlapping.rs:LL:CC
|
LL | copy_nonoverlapping(a, b, 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy_nonoverlapping called on overlapping ranges
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds
error: Undefined Behavior: out-of-bounds `offset_from`: ALLOC has size 4, so pointer at offset 10 is out-of-bounds
--> $DIR/ptr_offset_from_oob.rs:LL:CC
|
LL | unsafe { end_ptr.offset_from(end_ptr) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC has size 4, so pointer at offset 10 is out-of-bounds
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information