2023-05-17 10:30:14 +00:00
|
|
|
use std::mem;
|
2019-12-25 01:04:32 +01:00
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::mir::AssertKind;
|
2023-05-17 10:30:14 +00:00
|
|
|
use rustc_middle::ty::TyCtxt;
|
2023-05-16 01:53:21 +02:00
|
|
|
use rustc_middle::ty::{layout::LayoutError, ConstInt};
|
2023-05-17 10:30:14 +00:00
|
|
|
use rustc_span::source_map::Spanned;
|
|
|
|
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
2020-02-09 16:51:36 +01:00
|
|
|
|
2019-12-25 01:06:51 +01:00
|
|
|
use super::InterpCx;
|
2023-05-17 10:30:14 +00:00
|
|
|
use crate::errors::{self, FrameNote, ReportErrorExt};
|
|
|
|
use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, Machine, MachineStopType};
|
2020-02-08 22:21:20 +01:00
|
|
|
|
|
|
|
/// The CTFE machine has some custom error kinds.
|
2019-12-25 01:04:32 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2020-02-08 22:21:20 +01:00
|
|
|
pub enum ConstEvalErrKind {
|
2019-12-25 01:04:32 +01:00
|
|
|
ConstAccessesStatic,
|
2020-03-21 19:19:10 +01:00
|
|
|
ModifiedGlobal,
|
2020-06-19 18:57:15 +02:00
|
|
|
AssertFailure(AssertKind<ConstInt>),
|
2020-02-09 16:51:36 +01:00
|
|
|
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
|
2020-12-05 17:32:19 +01:00
|
|
|
Abort(String),
|
2019-12-25 01:04:32 +01:00
|
|
|
}
|
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
impl MachineStopType for ConstEvalErrKind {
|
|
|
|
fn diagnostic_message(&self) -> DiagnosticMessage {
|
|
|
|
use crate::fluent_generated::*;
|
|
|
|
use ConstEvalErrKind::*;
|
|
|
|
match self {
|
|
|
|
ConstAccessesStatic => const_eval_const_accesses_static,
|
|
|
|
ModifiedGlobal => const_eval_modified_global,
|
|
|
|
Panic { .. } => const_eval_panic,
|
|
|
|
AssertFailure(x) => x.diagnostic_message(),
|
|
|
|
Abort(msg) => msg.to_string().into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn add_args(
|
|
|
|
self: Box<Self>,
|
|
|
|
adder: &mut dyn FnMut(std::borrow::Cow<'static, str>, DiagnosticArgValue<'static>),
|
|
|
|
) {
|
|
|
|
use ConstEvalErrKind::*;
|
|
|
|
match *self {
|
|
|
|
ConstAccessesStatic | ModifiedGlobal | Abort(_) => {}
|
|
|
|
AssertFailure(kind) => kind.add_args(adder),
|
|
|
|
Panic { msg, line, col, file } => {
|
|
|
|
adder("msg".into(), msg.into_diagnostic_arg());
|
|
|
|
adder("file".into(), file.into_diagnostic_arg());
|
|
|
|
adder("line".into(), line.into_diagnostic_arg());
|
|
|
|
adder("col".into(), col.into_diagnostic_arg());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-25 20:54:59 -05:00
|
|
|
|
2020-02-08 22:21:20 +01:00
|
|
|
// The errors become `MachineStop` with plain strings when being raised.
|
2020-03-29 15:24:45 +02:00
|
|
|
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
|
2020-02-08 22:21:20 +01:00
|
|
|
// handle these.
|
|
|
|
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
|
2019-12-25 01:04:32 +01:00
|
|
|
fn into(self) -> InterpErrorInfo<'tcx> {
|
2021-05-25 20:54:59 -05:00
|
|
|
err_machine_stop!(self).into()
|
2019-12-25 01:04:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
pub fn get_span_and_frames<'tcx, 'mir, M: Machine<'mir, 'tcx>>(
|
|
|
|
ecx: &InterpCx<'mir, 'tcx, M>,
|
|
|
|
) -> (Span, Vec<errors::FrameNote>)
|
|
|
|
where
|
|
|
|
'tcx: 'mir,
|
|
|
|
{
|
|
|
|
let mut stacktrace = ecx.generate_stacktrace();
|
|
|
|
// Filter out `requires_caller_location` frames.
|
|
|
|
stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx));
|
|
|
|
let span = stacktrace.first().map(|f| f.span).unwrap_or(ecx.tcx.span);
|
2019-12-25 01:06:51 +01:00
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
let mut frames = Vec::new();
|
2020-08-09 15:37:32 +02:00
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
// Add notes to the backtrace. Don't print a single-line backtrace though.
|
|
|
|
if stacktrace.len() > 1 {
|
|
|
|
// Helper closure to print duplicated lines.
|
|
|
|
let mut add_frame = |mut frame: errors::FrameNote| {
|
|
|
|
frames.push(errors::FrameNote { times: 0, ..frame.clone() });
|
|
|
|
// Don't print [... additional calls ...] if the number of lines is small
|
|
|
|
if frame.times < 3 {
|
|
|
|
let times = frame.times;
|
|
|
|
frame.times = 0;
|
|
|
|
frames.extend(std::iter::repeat(frame).take(times as usize));
|
|
|
|
} else {
|
|
|
|
frames.push(frame);
|
2022-11-22 12:00:07 +00:00
|
|
|
}
|
2023-05-17 10:30:14 +00:00
|
|
|
};
|
2022-11-22 12:00:07 +00:00
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
let mut last_frame: Option<errors::FrameNote> = None;
|
|
|
|
for frame_info in &stacktrace {
|
|
|
|
let frame = frame_info.as_note(*ecx.tcx);
|
|
|
|
match last_frame.as_mut() {
|
|
|
|
Some(last_frame)
|
|
|
|
if last_frame.span == frame.span
|
|
|
|
&& last_frame.where_ == frame.where_
|
|
|
|
&& last_frame.instance == frame.instance =>
|
|
|
|
{
|
|
|
|
last_frame.times += 1;
|
|
|
|
}
|
|
|
|
Some(last_frame) => {
|
|
|
|
add_frame(mem::replace(last_frame, frame));
|
|
|
|
}
|
|
|
|
None => {
|
2022-11-22 12:00:07 +00:00
|
|
|
last_frame = Some(frame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-17 10:30:14 +00:00
|
|
|
if let Some(frame) = last_frame {
|
|
|
|
add_frame(frame);
|
|
|
|
}
|
2022-11-22 12:00:07 +00:00
|
|
|
}
|
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
(span, frames)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a diagnostic for a const eval error.
|
|
|
|
///
|
|
|
|
/// This will use the `mk` function for creating the error which will get passed labels according to
|
|
|
|
/// the `InterpError` and the span and a stacktrace of current execution according to
|
|
|
|
/// `get_span_and_frames`.
|
|
|
|
pub(super) fn report<'tcx, C, F, E>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
error: InterpError<'tcx>,
|
|
|
|
span: Option<Span>,
|
|
|
|
get_span_and_frames: C,
|
|
|
|
mk: F,
|
|
|
|
) -> ErrorHandled
|
|
|
|
where
|
|
|
|
C: FnOnce() -> (Span, Vec<FrameNote>),
|
|
|
|
F: FnOnce(Span, Vec<FrameNote>) -> E,
|
|
|
|
E: IntoDiagnostic<'tcx, ErrorGuaranteed>,
|
|
|
|
{
|
|
|
|
// Special handling for certain errors
|
|
|
|
match error {
|
|
|
|
// Don't emit a new diagnostic for these errors
|
|
|
|
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
|
|
|
ErrorHandled::TooGeneric
|
|
|
|
}
|
2023-07-27 18:51:44 +00:00
|
|
|
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar),
|
|
|
|
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
|
|
|
|
ErrorHandled::Reported(guar.into())
|
|
|
|
}
|
2023-05-17 10:30:14 +00:00
|
|
|
err_inval!(Layout(layout_error @ LayoutError::SizeOverflow(_))) => {
|
|
|
|
// 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
|
|
|
|
// caller thinks anyway.
|
|
|
|
// See <https://github.com/rust-lang/rust/pull/63152>.
|
|
|
|
let (our_span, frames) = get_span_and_frames();
|
|
|
|
let span = span.unwrap_or(our_span);
|
|
|
|
let mut err =
|
|
|
|
tcx.sess.create_err(Spanned { span, node: layout_error.into_diagnostic() });
|
|
|
|
err.code(rustc_errors::error_code!(E0080));
|
|
|
|
let Some((mut err, handler)) = err.into_diagnostic() else {
|
|
|
|
panic!("did not emit diag");
|
|
|
|
};
|
|
|
|
for frame in frames {
|
|
|
|
err.eager_subdiagnostic(handler, frame);
|
2022-11-22 12:00:07 +00:00
|
|
|
}
|
2023-05-17 10:30:14 +00:00
|
|
|
|
|
|
|
ErrorHandled::Reported(handler.emit_diagnostic(&mut err).unwrap().into())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Report as hard error.
|
|
|
|
let (our_span, frames) = get_span_and_frames();
|
|
|
|
let span = span.unwrap_or(our_span);
|
|
|
|
let err = mk(span, frames);
|
|
|
|
let mut err = tcx.sess.create_err(err);
|
|
|
|
|
|
|
|
let msg = error.diagnostic_message();
|
|
|
|
error.add_args(&tcx.sess.parse_sess.span_diagnostic, &mut err);
|
|
|
|
|
|
|
|
// Use *our* span to label the interp error
|
|
|
|
err.span_label(our_span, msg);
|
|
|
|
ErrorHandled::Reported(err.emit().into())
|
2022-11-22 12:00:07 +00:00
|
|
|
}
|
2020-08-09 15:37:32 +02:00
|
|
|
}
|
2019-12-25 01:06:51 +01:00
|
|
|
}
|