4 use rustc_errors
::Diagnostic
;
6 use rustc_middle
::mir
::AssertKind
;
7 use rustc_middle
::ty
::{layout::LayoutError, query::TyCtxtAt, ConstInt}
;
8 use rustc_span
::{Span, Symbol}
;
11 use crate::interpret
::{
12 struct_error
, ErrorHandled
, FrameInfo
, InterpError
, InterpErrorInfo
, Machine
, MachineStopType
,
16 /// The CTFE machine has some custom error kinds.
17 #[derive(Clone, Debug)]
18 pub enum ConstEvalErrKind
{
21 AssertFailure(AssertKind
<ConstInt
>),
22 Panic { msg: Symbol, line: u32, col: u32, file: Symbol }
,
26 impl MachineStopType
for ConstEvalErrKind
{
27 fn is_hard_err(&self) -> bool
{
28 matches
!(self, Self::Panic { .. }
)
32 // The errors become `MachineStop` with plain strings when being raised.
33 // `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
35 impl<'tcx
> Into
<InterpErrorInfo
<'tcx
>> for ConstEvalErrKind
{
36 fn into(self) -> InterpErrorInfo
<'tcx
> {
37 err_machine_stop
!(self).into()
41 impl fmt
::Display
for ConstEvalErrKind
{
42 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
43 use self::ConstEvalErrKind
::*;
45 ConstAccessesStatic
=> write
!(f
, "constant accesses static"),
47 write
!(f
, "modifying a static's initial value from another static's initializer")
49 AssertFailure(ref msg
) => write
!(f
, "{:?}", msg
),
50 Panic { msg, line, col, file }
=> {
51 write
!(f
, "the evaluated program panicked at '{}', {}:{}:{}", msg
, file
, line
, col
)
53 Abort(ref msg
) => write
!(f
, "{}", msg
),
58 impl Error
for ConstEvalErrKind {}
60 /// When const-evaluation errors, this type is constructed with the resulting information,
61 /// and then used to emit the error as a lint or hard error.
63 pub struct ConstEvalErr
<'tcx
> {
65 pub error
: InterpError
<'tcx
>,
66 pub stacktrace
: Vec
<FrameInfo
<'tcx
>>,
69 impl<'tcx
> ConstEvalErr
<'tcx
> {
70 /// Turn an interpreter error into something to report to the user.
71 /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
72 /// Should be called only if the error is actually going to to be reported!
73 pub fn new
<'mir
, M
: Machine
<'mir
, 'tcx
>>(
74 ecx
: &InterpCx
<'mir
, 'tcx
, M
>,
75 error
: InterpErrorInfo
<'tcx
>,
77 ) -> ConstEvalErr
<'tcx
>
81 error
.print_backtrace();
82 let mut stacktrace
= ecx
.generate_stacktrace();
83 // Filter out `requires_caller_location` frames.
84 stacktrace
.retain(|frame
| !frame
.instance
.def
.requires_caller_location(*ecx
.tcx
));
85 // If `span` is missing, use topmost remaining frame, or else the "root" span from `ecx.tcx`.
86 let span
= span
.or_else(|| stacktrace
.first().map(|f
| f
.span
)).unwrap_or(ecx
.tcx
.span
);
87 ConstEvalErr { error: error.into_kind(), stacktrace, span }
94 decorate
: impl FnOnce(&mut Diagnostic
),
96 self.struct_generic(tcx
, message
, decorate
, None
)
99 pub fn report_as_error(&self, tcx
: TyCtxtAt
<'tcx
>, message
: &str) -> ErrorHandled
{
100 self.struct_error(tcx
, message
, |_
| {}
)
103 pub fn report_as_lint(
107 lint_root
: hir
::HirId
,
113 |lint
: &mut Diagnostic
| {
115 if let Some(span
) = span
{
116 let primary_spans
= lint
.span
.primary_spans().to_vec();
117 // point at the actual error as the primary span
118 lint
.replace_span_with(span
);
119 // point to the `const` statement as a secondary span
120 // they don't have any label
121 for sp
in primary_spans
{
123 lint
.span_label(sp
, "");
132 /// Create a diagnostic for this const eval error.
134 /// Sets the message passed in via `message` and adds span labels with detailed error
135 /// information before handing control back to `decorate` to do any final annotations,
136 /// after which the diagnostic is emitted.
138 /// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
139 /// (Except that for some errors, we ignore all that -- see `must_error` below.)
140 #[instrument(skip(self, tcx, decorate, lint_root), level = "debug")]
145 decorate
: impl FnOnce(&mut Diagnostic
),
146 lint_root
: Option
<hir
::HirId
>,
148 let finish
= |err
: &mut Diagnostic
, span_msg
: Option
<String
>| {
149 trace
!("reporting const eval failure at {:?}", self.span
);
150 if let Some(span_msg
) = span_msg
{
151 err
.span_label(self.span
, span_msg
);
153 // Add some more context for select error types.
155 InterpError
::Unsupported(
156 UnsupportedOpInfo
::ReadPointerAsBytes
157 | UnsupportedOpInfo
::PartialPointerOverwrite(_
)
158 | UnsupportedOpInfo
::PartialPointerCopy(_
),
160 err
.help("this code performed an operation that depends on the underlying bytes representing a pointer");
161 err
.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
165 // Add spans for the stacktrace. Don't print a single-line backtrace though.
166 if self.stacktrace
.len() > 1 {
167 // Helper closure to print duplicated lines.
168 let mut flush_last_line
= |last_frame
, times
| {
169 if let Some((line
, span
)) = last_frame
{
170 err
.span_label(span
, &line
);
171 // Don't print [... additional calls ...] if the number of lines is small
174 err
.span_label(span
, &line
);
179 format
!("[... {} additional calls {} ...]", times
, &line
),
185 let mut last_frame
= None
;
187 for frame_info
in &self.stacktrace
{
188 let frame
= (frame_info
.to_string(), frame_info
.span
);
189 if last_frame
.as_ref() == Some(&frame
) {
192 flush_last_line(last_frame
, times
);
193 last_frame
= Some(frame
);
197 flush_last_line(last_frame
, times
);
199 // Let the caller attach any additional information it wants.
203 debug
!("self.error: {:?}", self.error
);
204 // Special handling for certain errors
206 // Don't emit a new diagnostic for these errors
207 err_inval
!(Layout(LayoutError
::Unknown(_
))) | err_inval
!(TooGeneric
) => {
208 return ErrorHandled
::TooGeneric
;
210 err_inval
!(AlreadyReported(error_reported
)) => {
211 return ErrorHandled
::Reported(*error_reported
);
213 err_inval
!(Layout(LayoutError
::SizeOverflow(_
))) => {
214 // We must *always* hard error on these, even if the caller wants just a lint.
215 // The `message` makes little sense here, this is a more serious error than the
216 // caller thinks anyway.
217 // See <https://github.com/rust-lang/rust/pull/63152>.
218 let mut err
= struct_error(tcx
, &self.error
.to_string());
219 finish(&mut err
, None
);
220 return ErrorHandled
::Reported(err
.emit());
225 let err_msg
= self.error
.to_string();
227 // Regular case - emit a lint.
228 if let Some(lint_root
) = lint_root
{
231 self.stacktrace
.iter().rev().find_map(|frame
| frame
.lint_root
).unwrap_or(lint_root
);
232 tcx
.struct_span_lint_hir(
233 rustc_session
::lint
::builtin
::CONST_ERR
,
237 let mut lint
= lint
.build(message
);
238 finish(&mut lint
, Some(err_msg
));
244 // Report as hard error.
245 let mut err
= struct_error(tcx
, message
);
246 finish(&mut err
, Some(err_msg
));
247 ErrorHandled
::Reported(err
.emit())