]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_const_eval/src/const_eval/error.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_const_eval / src / const_eval / error.rs
CommitLineData
dfeec247
XL
1use std::error::Error;
2use std::fmt;
3
5e7ed085 4use rustc_errors::Diagnostic;
ba9703b0 5use rustc_middle::mir::AssertKind;
49aad941
FG
6use rustc_middle::query::TyCtxtAt;
7use rustc_middle::ty::{layout::LayoutError, ConstInt};
f035d41b 8use rustc_span::{Span, Symbol};
74b04a01 9
dfeec247 10use super::InterpCx;
3dfed10e 11use 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 18pub 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 26impl 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.
31impl<'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 37impl 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 54impl 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 59pub(super) struct ConstEvalErr<'tcx> {
3dfed10e
XL
60 pub span: Span,
61 pub error: InterpError<'tcx>,
62 pub stacktrace: Vec<FrameInfo<'tcx>>,
63}
64
65impl<'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}