2023-05-17 10:30:14 +00:00
|
|
|
use std::mem;
|
2019-12-25 01:04:32 +01:00
|
|
|
|
2024-03-06 11:02:56 +11:00
|
|
|
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg};
|
2023-11-26 16:57:13 +01:00
|
|
|
use rustc_hir::CRATE_HIR_ID;
|
2024-04-29 11:53:23 +00:00
|
|
|
use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::mir::AssertKind;
|
2023-11-26 16:57:13 +01:00
|
|
|
use rustc_middle::query::TyCtxtAt;
|
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};
|
2024-05-07 14:52:42 +02:00
|
|
|
use rustc_span::{Span, Symbol};
|
2020-02-09 16:51:36 +01:00
|
|
|
|
2024-03-11 13:20:12 +00:00
|
|
|
use super::CompileTimeInterpreter;
|
2023-05-17 10:30:14 +00:00
|
|
|
use crate::errors::{self, FrameNote, ReportErrorExt};
|
2024-05-08 19:03:14 +10:00
|
|
|
use crate::interpret::{err_inval, err_machine_stop};
|
2024-03-11 13:20:12 +00:00
|
|
|
use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, 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 {
|
2024-01-05 12:18:11 +01:00
|
|
|
ConstAccessesMutGlobal,
|
2020-03-21 19:19:10 +01:00
|
|
|
ModifiedGlobal,
|
2023-10-12 11:27:43 +00:00
|
|
|
RecursiveStatic,
|
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 },
|
2019-12-25 01:04:32 +01:00
|
|
|
}
|
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
impl MachineStopType for ConstEvalErrKind {
|
2024-02-29 11:58:51 +11:00
|
|
|
fn diagnostic_message(&self) -> DiagMessage {
|
2023-05-17 10:30:14 +00:00
|
|
|
use crate::fluent_generated::*;
|
|
|
|
use ConstEvalErrKind::*;
|
|
|
|
match self {
|
2024-01-05 12:18:11 +01:00
|
|
|
ConstAccessesMutGlobal => const_eval_const_accesses_mut_global,
|
2023-05-17 10:30:14 +00:00
|
|
|
ModifiedGlobal => const_eval_modified_global,
|
|
|
|
Panic { .. } => const_eval_panic,
|
2023-10-12 11:27:43 +00:00
|
|
|
RecursiveStatic => const_eval_recursive_static,
|
2023-05-17 10:30:14 +00:00
|
|
|
AssertFailure(x) => x.diagnostic_message(),
|
|
|
|
}
|
|
|
|
}
|
2024-02-23 14:37:48 +11:00
|
|
|
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
|
2023-05-17 10:30:14 +00:00
|
|
|
use ConstEvalErrKind::*;
|
|
|
|
match *self {
|
2023-10-12 11:27:43 +00:00
|
|
|
RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {}
|
2023-05-17 10:30:14 +00:00
|
|
|
AssertFailure(kind) => kind.add_args(adder),
|
|
|
|
Panic { msg, line, col, file } => {
|
2024-03-05 16:53:24 +11:00
|
|
|
adder("msg".into(), msg.into_diag_arg());
|
|
|
|
adder("file".into(), file.into_diag_arg());
|
|
|
|
adder("line".into(), line.into_diag_arg());
|
|
|
|
adder("col".into(), col.into_diag_arg());
|
2023-05-17 10:30:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-25 20:54:59 -05:00
|
|
|
|
2024-01-05 02:52:37 +00:00
|
|
|
/// The errors become [`InterpError::MachineStop`] when being raised.
|
2020-02-08 22:21:20 +01:00
|
|
|
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-11-26 16:57:13 +01:00
|
|
|
pub fn get_span_and_frames<'tcx, 'mir>(
|
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2024-03-11 13:21:42 +00:00
|
|
|
stack: &[Frame<'mir, 'tcx, impl Provenance, impl Sized>],
|
2023-05-17 10:30:14 +00:00
|
|
|
) -> (Span, Vec<errors::FrameNote>)
|
|
|
|
where
|
|
|
|
'tcx: 'mir,
|
|
|
|
{
|
2024-03-11 13:21:42 +00:00
|
|
|
let mut stacktrace = Frame::generate_stacktrace_from_stack(stack);
|
2023-05-17 10:30:14 +00:00
|
|
|
// Filter out `requires_caller_location` frames.
|
2023-11-26 16:57:13 +01:00
|
|
|
stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
|
|
|
|
let span = stacktrace.first().map(|f| f.span).unwrap_or(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 {
|
2023-11-26 16:57:13 +01:00
|
|
|
let frame = frame_info.as_note(*tcx);
|
2023-05-17 10:30:14 +00:00
|
|
|
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>,
|
2024-05-07 14:52:42 +02:00
|
|
|
span: Span,
|
2023-05-17 10:30:14 +00:00
|
|
|
get_span_and_frames: C,
|
|
|
|
mk: F,
|
|
|
|
) -> ErrorHandled
|
|
|
|
where
|
|
|
|
C: FnOnce() -> (Span, Vec<FrameNote>),
|
|
|
|
F: FnOnce(Span, Vec<FrameNote>) -> E,
|
2024-03-06 11:02:56 +11:00
|
|
|
E: Diagnostic<'tcx>,
|
2023-05-17 10:30:14 +00:00
|
|
|
{
|
|
|
|
// Special handling for certain errors
|
|
|
|
match error {
|
2023-09-12 13:41:42 +02:00
|
|
|
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or
|
|
|
|
// should remain silent.
|
2023-05-17 10:30:14 +00:00
|
|
|
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
2024-05-07 14:52:42 +02:00
|
|
|
ErrorHandled::TooGeneric(span)
|
2023-05-17 10:30:14 +00:00
|
|
|
}
|
2024-05-07 14:52:42 +02:00
|
|
|
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span),
|
2024-04-29 11:53:23 +00:00
|
|
|
err_inval!(Layout(LayoutError::ReferencesError(guar))) => ErrorHandled::Reported(
|
|
|
|
ReportedErrorInfo::tainted_by_errors(guar),
|
|
|
|
span,
|
|
|
|
),
|
2023-09-12 13:41:42 +02:00
|
|
|
// Report remaining errors.
|
2023-05-17 10:30:14 +00:00
|
|
|
_ => {
|
|
|
|
let (our_span, frames) = get_span_and_frames();
|
2024-05-07 14:52:42 +02:00
|
|
|
let span = span.substitute_dummy(our_span);
|
2023-05-17 10:30:14 +00:00
|
|
|
let err = mk(span, frames);
|
2023-12-18 22:21:37 +11:00
|
|
|
let mut err = tcx.dcx().create_err(err);
|
2023-05-17 10:30:14 +00:00
|
|
|
|
|
|
|
let msg = error.diagnostic_message();
|
2024-02-12 15:18:18 +11:00
|
|
|
error.add_args(&mut err);
|
2023-05-17 10:30:14 +00:00
|
|
|
|
|
|
|
// Use *our* span to label the interp error
|
|
|
|
err.span_label(our_span, msg);
|
2023-09-11 09:52:45 +02:00
|
|
|
ErrorHandled::Reported(err.emit().into(), span)
|
2022-11-22 12:00:07 +00:00
|
|
|
}
|
2020-08-09 15:37:32 +02:00
|
|
|
}
|
2019-12-25 01:06:51 +01:00
|
|
|
}
|
2023-11-26 16:57:13 +01:00
|
|
|
|
|
|
|
/// Emit a lint from a const-eval situation.
|
|
|
|
// Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future!
|
|
|
|
pub(super) fn lint<'tcx, 'mir, L>(
|
|
|
|
tcx: TyCtxtAt<'tcx>,
|
|
|
|
machine: &CompileTimeInterpreter<'mir, 'tcx>,
|
|
|
|
lint: &'static rustc_session::lint::Lint,
|
|
|
|
decorator: impl FnOnce(Vec<errors::FrameNote>) -> L,
|
|
|
|
) where
|
2024-03-08 12:03:51 +11:00
|
|
|
L: for<'a> rustc_errors::LintDiagnostic<'a, ()>,
|
2023-11-26 16:57:13 +01:00
|
|
|
{
|
2024-03-11 13:21:42 +00:00
|
|
|
let (span, frames) = get_span_and_frames(tcx, &machine.stack);
|
2023-11-26 16:57:13 +01:00
|
|
|
|
2024-01-16 16:27:02 +11:00
|
|
|
tcx.emit_node_span_lint(
|
2023-11-26 16:57:13 +01:00
|
|
|
lint,
|
|
|
|
// We use the root frame for this so the crate that defines the const defines whether the
|
|
|
|
// lint is emitted.
|
|
|
|
machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
|
|
|
|
span,
|
|
|
|
decorator(frames),
|
|
|
|
);
|
|
|
|
}
|