]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_const_eval/src/const_eval/error.rs
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[rustc.git] / compiler / rustc_const_eval / src / const_eval / error.rs
1 use std::mem;
2
3 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg};
4 use rustc_hir::CRATE_HIR_ID;
5 use rustc_middle::mir::interpret::Provenance;
6 use rustc_middle::mir::AssertKind;
7 use rustc_middle::query::TyCtxtAt;
8 use rustc_middle::ty::TyCtxt;
9 use rustc_middle::ty::{layout::LayoutError, ConstInt};
10 use rustc_span::{Span, Symbol, DUMMY_SP};
11
12 use super::CompileTimeInterpreter;
13 use crate::errors::{self, FrameNote, ReportErrorExt};
14 use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType};
15
16 /// The CTFE machine has some custom error kinds.
17 #[derive(Clone, Debug)]
18 pub enum ConstEvalErrKind {
19 ConstAccessesMutGlobal,
20 ModifiedGlobal,
21 RecursiveStatic,
22 AssertFailure(AssertKind<ConstInt>),
23 Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
24 }
25
26 impl MachineStopType for ConstEvalErrKind {
27 fn diagnostic_message(&self) -> DiagMessage {
28 use crate::fluent_generated::*;
29 use ConstEvalErrKind::*;
30 match self {
31 ConstAccessesMutGlobal => const_eval_const_accesses_mut_global,
32 ModifiedGlobal => const_eval_modified_global,
33 Panic { .. } => const_eval_panic,
34 RecursiveStatic => const_eval_recursive_static,
35 AssertFailure(x) => x.diagnostic_message(),
36 }
37 }
38 fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
39 use ConstEvalErrKind::*;
40 match *self {
41 RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {}
42 AssertFailure(kind) => kind.add_args(adder),
43 Panic { msg, line, col, file } => {
44 adder("msg".into(), msg.into_diag_arg());
45 adder("file".into(), file.into_diag_arg());
46 adder("line".into(), line.into_diag_arg());
47 adder("col".into(), col.into_diag_arg());
48 }
49 }
50 }
51 }
52
53 /// The errors become [`InterpError::MachineStop`] when being raised.
54 impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
55 fn into(self) -> InterpErrorInfo<'tcx> {
56 err_machine_stop!(self).into()
57 }
58 }
59
60 pub fn get_span_and_frames<'tcx, 'mir>(
61 tcx: TyCtxtAt<'tcx>,
62 stack: &[Frame<'mir, 'tcx, impl Provenance, impl Sized>],
63 ) -> (Span, Vec<errors::FrameNote>)
64 where
65 'tcx: 'mir,
66 {
67 let mut stacktrace = Frame::generate_stacktrace_from_stack(stack);
68 // Filter out `requires_caller_location` frames.
69 stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
70 let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span);
71
72 let mut frames = Vec::new();
73
74 // Add notes to the backtrace. Don't print a single-line backtrace though.
75 if stacktrace.len() > 1 {
76 // Helper closure to print duplicated lines.
77 let mut add_frame = |mut frame: errors::FrameNote| {
78 frames.push(errors::FrameNote { times: 0, ..frame.clone() });
79 // Don't print [... additional calls ...] if the number of lines is small
80 if frame.times < 3 {
81 let times = frame.times;
82 frame.times = 0;
83 frames.extend(std::iter::repeat(frame).take(times as usize));
84 } else {
85 frames.push(frame);
86 }
87 };
88
89 let mut last_frame: Option<errors::FrameNote> = None;
90 for frame_info in &stacktrace {
91 let frame = frame_info.as_note(*tcx);
92 match last_frame.as_mut() {
93 Some(last_frame)
94 if last_frame.span == frame.span
95 && last_frame.where_ == frame.where_
96 && last_frame.instance == frame.instance =>
97 {
98 last_frame.times += 1;
99 }
100 Some(last_frame) => {
101 add_frame(mem::replace(last_frame, frame));
102 }
103 None => {
104 last_frame = Some(frame);
105 }
106 }
107 }
108 if let Some(frame) = last_frame {
109 add_frame(frame);
110 }
111 }
112
113 (span, frames)
114 }
115
116 /// Create a diagnostic for a const eval error.
117 ///
118 /// This will use the `mk` function for creating the error which will get passed labels according to
119 /// the `InterpError` and the span and a stacktrace of current execution according to
120 /// `get_span_and_frames`.
121 pub(super) fn report<'tcx, C, F, E>(
122 tcx: TyCtxt<'tcx>,
123 error: InterpError<'tcx>,
124 span: Option<Span>,
125 get_span_and_frames: C,
126 mk: F,
127 ) -> ErrorHandled
128 where
129 C: FnOnce() -> (Span, Vec<FrameNote>),
130 F: FnOnce(Span, Vec<FrameNote>) -> E,
131 E: Diagnostic<'tcx>,
132 {
133 // Special handling for certain errors
134 match error {
135 // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
136 // should remain silent.
137 err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
138 ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))
139 }
140 err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)),
141 err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
142 ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
143 }
144 // Report remaining errors.
145 _ => {
146 let (our_span, frames) = get_span_and_frames();
147 let span = span.unwrap_or(our_span);
148 let err = mk(span, frames);
149 let mut err = tcx.dcx().create_err(err);
150
151 let msg = error.diagnostic_message();
152 error.add_args(&mut err);
153
154 // Use *our* span to label the interp error
155 err.span_label(our_span, msg);
156 ErrorHandled::Reported(err.emit().into(), span)
157 }
158 }
159 }
160
161 /// Emit a lint from a const-eval situation.
162 // 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!
163 pub(super) fn lint<'tcx, 'mir, L>(
164 tcx: TyCtxtAt<'tcx>,
165 machine: &CompileTimeInterpreter<'mir, 'tcx>,
166 lint: &'static rustc_session::lint::Lint,
167 decorator: impl FnOnce(Vec<errors::FrameNote>) -> L,
168 ) where
169 L: for<'a> rustc_errors::LintDiagnostic<'a, ()>,
170 {
171 let (span, frames) = get_span_and_frames(tcx, &machine.stack);
172
173 tcx.emit_node_span_lint(
174 lint,
175 // We use the root frame for this so the crate that defines the const defines whether the
176 // lint is emitted.
177 machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
178 span,
179 decorator(frames),
180 );
181 }