rustc_const_eval/const_eval/
error.rs1use std::mem;
2
3use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg};
4use rustc_middle::mir::AssertKind;
5use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo, UndefinedBehaviorInfo};
6use rustc_middle::query::TyCtxtAt;
7use rustc_middle::ty::ConstInt;
8use rustc_middle::ty::layout::LayoutError;
9use rustc_span::{Span, Symbol};
10
11use super::CompileTimeMachine;
12use crate::errors::{self, FrameNote, ReportErrorExt};
13use crate::interpret::{
14 CtfeProvenance, ErrorHandled, Frame, InterpCx, InterpErrorInfo, InterpErrorKind,
15 MachineStopType, Pointer, err_inval, err_machine_stop,
16};
17
18#[derive(#[automatically_derived]
impl ::core::clone::Clone for ConstEvalErrKind {
#[inline]
fn clone(&self) -> ConstEvalErrKind {
match self {
ConstEvalErrKind::ConstAccessesMutGlobal =>
ConstEvalErrKind::ConstAccessesMutGlobal,
ConstEvalErrKind::ModifiedGlobal =>
ConstEvalErrKind::ModifiedGlobal,
ConstEvalErrKind::RecursiveStatic =>
ConstEvalErrKind::RecursiveStatic,
ConstEvalErrKind::AssertFailure(__self_0) =>
ConstEvalErrKind::AssertFailure(::core::clone::Clone::clone(__self_0)),
ConstEvalErrKind::Panic {
msg: __self_0, line: __self_1, col: __self_2, file: __self_3 }
=>
ConstEvalErrKind::Panic {
msg: ::core::clone::Clone::clone(__self_0),
line: ::core::clone::Clone::clone(__self_1),
col: ::core::clone::Clone::clone(__self_2),
file: ::core::clone::Clone::clone(__self_3),
},
ConstEvalErrKind::WriteThroughImmutablePointer =>
ConstEvalErrKind::WriteThroughImmutablePointer,
ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(__self_0) =>
ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(::core::clone::Clone::clone(__self_0)),
ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(__self_0) =>
ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(::core::clone::Clone::clone(__self_0)),
ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(__self_0) =>
ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(::core::clone::Clone::clone(__self_0)),
ConstEvalErrKind::ConstMakeGlobalWithOffset(__self_0) =>
ConstEvalErrKind::ConstMakeGlobalWithOffset(::core::clone::Clone::clone(__self_0)),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for ConstEvalErrKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ConstEvalErrKind::ConstAccessesMutGlobal =>
::core::fmt::Formatter::write_str(f,
"ConstAccessesMutGlobal"),
ConstEvalErrKind::ModifiedGlobal =>
::core::fmt::Formatter::write_str(f, "ModifiedGlobal"),
ConstEvalErrKind::RecursiveStatic =>
::core::fmt::Formatter::write_str(f, "RecursiveStatic"),
ConstEvalErrKind::AssertFailure(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AssertFailure", &__self_0),
ConstEvalErrKind::Panic {
msg: __self_0, line: __self_1, col: __self_2, file: __self_3 }
=>
::core::fmt::Formatter::debug_struct_field4_finish(f, "Panic",
"msg", __self_0, "line", __self_1, "col", __self_2, "file",
&__self_3),
ConstEvalErrKind::WriteThroughImmutablePointer =>
::core::fmt::Formatter::write_str(f,
"WriteThroughImmutablePointer"),
ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ConstMakeGlobalPtrAlreadyMadeGlobal", &__self_0),
ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ConstMakeGlobalPtrIsNonHeap", &__self_0),
ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ConstMakeGlobalWithDanglingPtr", &__self_0),
ConstEvalErrKind::ConstMakeGlobalWithOffset(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ConstMakeGlobalWithOffset", &__self_0),
}
}
}Debug)]
20pub enum ConstEvalErrKind {
21 ConstAccessesMutGlobal,
22 ModifiedGlobal,
23 RecursiveStatic,
24 AssertFailure(AssertKind<ConstInt>),
25 Panic {
26 msg: Symbol,
27 line: u32,
28 col: u32,
29 file: Symbol,
30 },
31 WriteThroughImmutablePointer,
32 ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId),
34 ConstMakeGlobalPtrIsNonHeap(Pointer<Option<CtfeProvenance>>),
36 ConstMakeGlobalWithDanglingPtr(Pointer<Option<CtfeProvenance>>),
38 ConstMakeGlobalWithOffset(Pointer<Option<CtfeProvenance>>),
41}
42
43impl MachineStopType for ConstEvalErrKind {
44 fn diagnostic_message(&self) -> DiagMessage {
45 use ConstEvalErrKind::*;
46 use rustc_errors::inline_fluent;
47
48 match self {
49 ConstAccessesMutGlobal => "constant accesses mutable global memory".into(),
50 ModifiedGlobal => {
51 "modifying a static's initial value from another static's initializer".into()
52 }
53 Panic { .. } => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("evaluation panicked: {$msg}"))inline_fluent!("evaluation panicked: {$msg}"),
54 RecursiveStatic => {
55 "encountered static that tried to access itself during initialization".into()
56 }
57 AssertFailure(x) => x.diagnostic_message(),
58 WriteThroughImmutablePointer => {
59 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("writing through a pointer that was derived from a shared (immutable) reference"))inline_fluent!(
60 "writing through a pointer that was derived from a shared (immutable) reference"
61 )
62 }
63 ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
64 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempting to call `const_make_global` twice on the same allocation {$alloc}"))inline_fluent!(
65 "attempting to call `const_make_global` twice on the same allocation {$alloc}"
66 )
67 }
68 ConstMakeGlobalPtrIsNonHeap(_) => {
69 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}"))inline_fluent!(
70 "pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}"
71 )
72 }
73 ConstMakeGlobalWithDanglingPtr(_) => {
74 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("pointer passed to `const_make_global` is dangling: {$ptr}"))inline_fluent!("pointer passed to `const_make_global` is dangling: {$ptr}")
75 }
76 ConstMakeGlobalWithOffset(_) => {
77 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("making {$ptr} global which does not point to the beginning of an object"))inline_fluent!(
78 "making {$ptr} global which does not point to the beginning of an object"
79 )
80 }
81 }
82 }
83 fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
84 use ConstEvalErrKind::*;
85 match *self {
86 RecursiveStatic
87 | ConstAccessesMutGlobal
88 | ModifiedGlobal
89 | WriteThroughImmutablePointer => {}
90 AssertFailure(kind) => kind.add_args(adder),
91 Panic { msg, .. } => {
92 adder("msg".into(), msg.into_diag_arg(&mut None));
93 }
94 ConstMakeGlobalPtrIsNonHeap(ptr)
95 | ConstMakeGlobalWithOffset(ptr)
96 | ConstMakeGlobalWithDanglingPtr(ptr) => {
97 adder("ptr".into(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", ptr))
})format!("{ptr:?}").into_diag_arg(&mut None));
98 }
99 ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => {
100 adder("alloc".into(), alloc.into_diag_arg(&mut None));
101 }
102 }
103 }
104}
105
106impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
108 fn into(self) -> InterpErrorInfo<'tcx> {
109 ::rustc_middle::mir::interpret::InterpErrorKind::MachineStop(Box::new(self))err_machine_stop!(self).into()
110 }
111}
112
113pub fn get_span_and_frames<'tcx>(
114 tcx: TyCtxtAt<'tcx>,
115 stack: &[Frame<'tcx, impl Provenance, impl Sized>],
116) -> (Span, Vec<errors::FrameNote>) {
117 let mut stacktrace = Frame::generate_stacktrace_from_stack(stack);
118 stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
120 let span = stacktrace.last().map(|f| f.span).unwrap_or(tcx.span);
121
122 let mut frames = Vec::new();
123
124 if stacktrace.len() > 1 {
126 let mut add_frame = |mut frame: errors::FrameNote| {
128 frames.push(errors::FrameNote { times: 0, ..frame.clone() });
129 if frame.times < 3 {
131 let times = frame.times;
132 frame.times = 0;
133 frames.extend(std::iter::repeat_n(frame, times as usize));
134 } else {
135 frames.push(frame);
136 }
137 };
138
139 let mut last_frame: Option<errors::FrameNote> = None;
140 for frame_info in &stacktrace {
141 let frame = frame_info.as_note(*tcx);
142 match last_frame.as_mut() {
143 Some(last_frame)
144 if last_frame.span == frame.span
145 && last_frame.where_ == frame.where_
146 && last_frame.instance == frame.instance =>
147 {
148 last_frame.times += 1;
149 }
150 Some(last_frame) => {
151 add_frame(mem::replace(last_frame, frame));
152 }
153 None => {
154 last_frame = Some(frame);
155 }
156 }
157 }
158 if let Some(frame) = last_frame {
159 add_frame(frame);
160 }
161 }
162
163 frames.reverse();
167 if frames.len() > 0 {
168 frames.remove(0);
169 }
170 if let Some(last) = frames.last_mut()
171 && tcx.sess.source_map().span_to_snippet(last.span.source_callsite()).is_ok()
173 {
174 last.has_label = true;
175 }
176
177 (span, frames)
178}
179
180pub(super) fn report<'tcx, C, F>(
186 ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
187 error: InterpErrorKind<'tcx>,
188 span: Span,
189 get_span_and_frames: C,
190 mk: F,
191) -> ErrorHandled
192where
193 C: FnOnce() -> (Span, Vec<FrameNote>),
194 F: FnOnce(&mut Diag<'_>, Span, Vec<FrameNote>),
195{
196 let tcx = ecx.tcx.tcx;
197 match error {
199 ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::AlreadyReported(info))err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, span),
202 ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::Layout(LayoutError::TooGeneric(_)))err_inval!(Layout(LayoutError::TooGeneric(_))) | ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::TooGeneric)err_inval!(TooGeneric) => {
203 ErrorHandled::TooGeneric(span)
204 }
205 ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::Layout(LayoutError::ReferencesError(guar)))err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
206 ErrorHandled::Reported(ReportedErrorInfo::allowed_in_infallible(guar), span)
209 }
210 _ => {
212 let (our_span, frames) = get_span_and_frames();
213 let span = span.substitute_dummy(our_span);
214 let mut err = tcx.dcx().struct_span_err(our_span, error.diagnostic_message());
215 let allowed_in_infallible = #[allow(non_exhaustive_omitted_patterns)] match error {
InterpErrorKind::ResourceExhaustion(_) |
InterpErrorKind::InvalidProgram(_) => true,
_ => false,
}matches!(
218 error,
219 InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_)
220 );
221
222 if let InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(
223 Some((alloc_id, _access)),
224 )) = error
225 {
226 let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
227 let info = ecx.get_alloc_info(alloc_id);
228 let raw_bytes = errors::RawBytesNote {
229 size: info.size.bytes(),
230 align: info.align.bytes(),
231 bytes,
232 };
233 err.subdiagnostic(raw_bytes);
234 }
235
236 error.add_args(&mut err);
237
238 mk(&mut err, span, frames);
239 let g = err.emit();
240 let reported = if allowed_in_infallible {
241 ReportedErrorInfo::allowed_in_infallible(g)
242 } else {
243 ReportedErrorInfo::const_eval_error(g)
244 };
245 ErrorHandled::Reported(reported, span)
246 }
247 }
248}
249
250#[allow(unused)]
253pub(super) fn lint<'tcx, L>(
254 tcx: TyCtxtAt<'tcx>,
255 machine: &CompileTimeMachine<'tcx>,
256 lint: &'static rustc_session::lint::Lint,
257 decorator: impl FnOnce(Vec<errors::FrameNote>) -> L,
258) where
259 L: for<'a> rustc_errors::LintDiagnostic<'a, ()>,
260{
261 let (span, frames) = get_span_and_frames(tcx, &machine.stack);
262
263 tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames));
264}