]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use std::error::Error; |
2 | use std::fmt; | |
3 | ||
5e7ed085 | 4 | use rustc_errors::Diagnostic; |
ba9703b0 | 5 | use rustc_middle::mir::AssertKind; |
49aad941 FG |
6 | use rustc_middle::query::TyCtxtAt; |
7 | use rustc_middle::ty::{layout::LayoutError, ConstInt}; | |
f035d41b | 8 | use rustc_span::{Span, Symbol}; |
74b04a01 | 9 | |
dfeec247 | 10 | use super::InterpCx; |
3dfed10e | 11 | use crate::interpret::{ |
f2b60f7d FG |
12 | struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, |
13 | UnsupportedOpInfo, | |
3dfed10e | 14 | }; |
74b04a01 XL |
15 | |
16 | /// The CTFE machine has some custom error kinds. | |
dfeec247 | 17 | #[derive(Clone, Debug)] |
74b04a01 | 18 | pub enum ConstEvalErrKind { |
dfeec247 | 19 | ConstAccessesStatic, |
ba9703b0 | 20 | ModifiedGlobal, |
f035d41b | 21 | AssertFailure(AssertKind<ConstInt>), |
74b04a01 | 22 | Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, |
fc512014 | 23 | Abort(String), |
dfeec247 XL |
24 | } |
25 | ||
2b03887a | 26 | impl MachineStopType for ConstEvalErrKind {} |
17df50a5 | 27 | |
74b04a01 | 28 | // The errors become `MachineStop` with plain strings when being raised. |
ba9703b0 | 29 | // `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to |
74b04a01 XL |
30 | // handle these. |
31 | impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind { | |
dfeec247 | 32 | fn into(self) -> InterpErrorInfo<'tcx> { |
17df50a5 | 33 | err_machine_stop!(self).into() |
dfeec247 XL |
34 | } |
35 | } | |
36 | ||
74b04a01 | 37 | impl fmt::Display for ConstEvalErrKind { |
dfeec247 | 38 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
74b04a01 | 39 | use self::ConstEvalErrKind::*; |
9c376795 | 40 | match self { |
dfeec247 | 41 | ConstAccessesStatic => write!(f, "constant accesses static"), |
ba9703b0 XL |
42 | ModifiedGlobal => { |
43 | write!(f, "modifying a static's initial value from another static's initializer") | |
44 | } | |
9c376795 | 45 | AssertFailure(msg) => write!(f, "{:?}", msg), |
74b04a01 XL |
46 | Panic { msg, line, col, file } => { |
47 | write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) | |
48 | } | |
9c376795 | 49 | Abort(msg) => write!(f, "{}", msg), |
dfeec247 XL |
50 | } |
51 | } | |
52 | } | |
53 | ||
74b04a01 | 54 | impl Error for ConstEvalErrKind {} |
dfeec247 | 55 | |
3dfed10e XL |
56 | /// When const-evaluation errors, this type is constructed with the resulting information, |
57 | /// and then used to emit the error as a lint or hard error. | |
58 | #[derive(Debug)] | |
487cf647 | 59 | pub(super) struct ConstEvalErr<'tcx> { |
3dfed10e XL |
60 | pub span: Span, |
61 | pub error: InterpError<'tcx>, | |
62 | pub stacktrace: Vec<FrameInfo<'tcx>>, | |
63 | } | |
64 | ||
65 | impl<'tcx> ConstEvalErr<'tcx> { | |
66 | /// Turn an interpreter error into something to report to the user. | |
67 | /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. | |
2b03887a | 68 | /// Should be called only if the error is actually going to be reported! |
3dfed10e XL |
69 | pub fn new<'mir, M: Machine<'mir, 'tcx>>( |
70 | ecx: &InterpCx<'mir, 'tcx, M>, | |
71 | error: InterpErrorInfo<'tcx>, | |
72 | span: Option<Span>, | |
73 | ) -> ConstEvalErr<'tcx> | |
74 | where | |
75 | 'tcx: 'mir, | |
76 | { | |
77 | error.print_backtrace(); | |
064997fb FG |
78 | let mut stacktrace = ecx.generate_stacktrace(); |
79 | // Filter out `requires_caller_location` frames. | |
80 | stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); | |
81 | // If `span` is missing, use topmost remaining frame, or else the "root" span from `ecx.tcx`. | |
82 | let span = span.or_else(|| stacktrace.first().map(|f| f.span)).unwrap_or(ecx.tcx.span); | |
83 | ConstEvalErr { error: error.into_kind(), stacktrace, span } | |
3dfed10e XL |
84 | } |
85 | ||
487cf647 FG |
86 | pub(super) fn report(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled { |
87 | self.report_decorated(tcx, message, |_| {}) | |
3dfed10e XL |
88 | } |
89 | ||
9c376795 FG |
90 | #[instrument(level = "trace", skip(self, decorate))] |
91 | pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) { | |
92 | trace!("reporting const eval failure at {:?}", self.span); | |
93 | // Add some more context for select error types. | |
94 | match self.error { | |
95 | InterpError::Unsupported( | |
96 | UnsupportedOpInfo::ReadPointerAsBytes | |
97 | | UnsupportedOpInfo::PartialPointerOverwrite(_) | |
98 | | UnsupportedOpInfo::PartialPointerCopy(_), | |
99 | ) => { | |
100 | err.help("this code performed an operation that depends on the underlying bytes representing a pointer"); | |
101 | err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported"); | |
102 | } | |
103 | _ => {} | |
104 | } | |
105 | // Add spans for the stacktrace. Don't print a single-line backtrace though. | |
106 | if self.stacktrace.len() > 1 { | |
107 | // Helper closure to print duplicated lines. | |
49aad941 | 108 | let mut flush_last_line = |last_frame: Option<(String, _)>, times| { |
9c376795 | 109 | if let Some((line, span)) = last_frame { |
49aad941 | 110 | err.span_note(span, line.clone()); |
9c376795 FG |
111 | // Don't print [... additional calls ...] if the number of lines is small |
112 | if times < 3 { | |
113 | for _ in 0..times { | |
49aad941 | 114 | err.span_note(span, line.clone()); |
9c376795 FG |
115 | } |
116 | } else { | |
117 | err.span_note( | |
118 | span, | |
119 | format!("[... {} additional calls {} ...]", times, &line), | |
120 | ); | |
121 | } | |
122 | } | |
123 | }; | |
124 | ||
125 | let mut last_frame = None; | |
126 | let mut times = 0; | |
127 | for frame_info in &self.stacktrace { | |
128 | let frame = (frame_info.to_string(), frame_info.span); | |
129 | if last_frame.as_ref() == Some(&frame) { | |
130 | times += 1; | |
131 | } else { | |
132 | flush_last_line(last_frame, times); | |
133 | last_frame = Some(frame); | |
134 | times = 0; | |
135 | } | |
136 | } | |
137 | flush_last_line(last_frame, times); | |
138 | } | |
139 | // Let the caller attach any additional information it wants. | |
140 | decorate(err); | |
141 | } | |
142 | ||
3dfed10e XL |
143 | /// Create a diagnostic for this const eval error. |
144 | /// | |
145 | /// Sets the message passed in via `message` and adds span labels with detailed error | |
5e7ed085 FG |
146 | /// information before handing control back to `decorate` to do any final annotations, |
147 | /// after which the diagnostic is emitted. | |
3dfed10e XL |
148 | /// |
149 | /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. | |
150 | /// (Except that for some errors, we ignore all that -- see `must_error` below.) | |
2b03887a | 151 | #[instrument(skip(self, tcx, decorate), level = "debug")] |
487cf647 | 152 | pub(super) fn report_decorated( |
3dfed10e XL |
153 | &self, |
154 | tcx: TyCtxtAt<'tcx>, | |
155 | message: &str, | |
5e7ed085 | 156 | decorate: impl FnOnce(&mut Diagnostic), |
3dfed10e | 157 | ) -> ErrorHandled { |
923072b8 | 158 | debug!("self.error: {:?}", self.error); |
17df50a5 XL |
159 | // Special handling for certain errors |
160 | match &self.error { | |
161 | // Don't emit a new diagnostic for these errors | |
162 | err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { | |
9c376795 | 163 | ErrorHandled::TooGeneric |
17df50a5 | 164 | } |
9c376795 | 165 | err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported), |
17df50a5 XL |
166 | err_inval!(Layout(LayoutError::SizeOverflow(_))) => { |
167 | // We must *always* hard error on these, even if the caller wants just a lint. | |
168 | // The `message` makes little sense here, this is a more serious error than the | |
169 | // caller thinks anyway. | |
170 | // See <https://github.com/rust-lang/rust/pull/63152>. | |
5e7ed085 | 171 | let mut err = struct_error(tcx, &self.error.to_string()); |
9c376795 | 172 | self.decorate(&mut err, decorate); |
49aad941 | 173 | ErrorHandled::Reported(err.emit().into()) |
3dfed10e | 174 | } |
9c376795 FG |
175 | _ => { |
176 | // Report as hard error. | |
177 | let mut err = struct_error(tcx, message); | |
178 | err.span_label(self.span, self.error.to_string()); | |
179 | self.decorate(&mut err, decorate); | |
49aad941 | 180 | ErrorHandled::Reported(err.emit().into()) |
9c376795 FG |
181 | } |
182 | } | |
3dfed10e | 183 | } |
dfeec247 | 184 | } |