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