4 use crate::hir::map::definitions::DefPathData;
6 use crate::ty::{self, Ty, layout};
7 use crate::ty::layout::{Size, Align, LayoutError};
8 use rustc_target::spec::abi::Abi;
9 use rustc_macros::HashStable;
11 use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef};
13 use backtrace::Backtrace;
15 use crate::ty::query::TyCtxtAt;
16 use errors::DiagnosticBuilder;
18 use syntax_pos::{Pos, Span};
19 use syntax::symbol::Symbol;
21 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable)]
22 pub enum ErrorHandled {
23 /// Already reported a lint or an error for this evaluation.
25 /// Don't emit an error, the evaluation failed because the MIR was generic
26 /// and the substs didn't fully monomorphize it.
31 pub fn assert_reported(self) {
33 ErrorHandled::Reported => {},
34 ErrorHandled::TooGeneric => bug!("MIR interpretation failed without reporting an error \
35 even though it was fully monomorphized"),
40 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
41 pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
43 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
44 pub struct ConstEvalErr<'tcx> {
46 pub error: crate::mir::interpret::InterpError<'tcx, u64>,
47 pub stacktrace: Vec<FrameInfo<'tcx>>,
50 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
51 pub struct FrameInfo<'tcx> {
52 /// This span is in the caller.
54 pub instance: ty::Instance<'tcx>,
55 pub lint_root: Option<hir::HirId>,
58 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 if tcx.def_key(self.instance.def_id()).disambiguated_data.data
62 == DefPathData::ClosureExpr
64 write!(f, "inside call to closure")?;
66 write!(f, "inside call to `{}`", self.instance)?;
68 if !self.call_site.is_dummy() {
69 let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo());
70 write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
77 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
78 pub fn struct_error(&self,
79 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
81 -> Result<DiagnosticBuilder<'tcx>, ErrorHandled>
83 self.struct_generic(tcx, message, None)
86 pub fn report_as_error(&self,
87 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
90 let err = self.struct_error(tcx, message);
94 ErrorHandled::Reported
100 pub fn report_as_lint(&self,
101 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
103 lint_root: hir::HirId,
106 let lint = self.struct_generic(
113 if let Some(span) = span {
114 let primary_spans = lint.span.primary_spans().to_vec();
115 // point at the actual error as the primary span
116 lint.replace_span_with(span);
117 // point to the `const` statement as a secondary span
118 // they don't have any label
119 for sp in primary_spans {
121 lint.span_label(sp, "");
126 ErrorHandled::Reported
134 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
136 lint_root: Option<hir::HirId>,
137 ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
139 InterpError::Layout(LayoutError::Unknown(_)) |
140 InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric),
141 InterpError::Layout(LayoutError::SizeOverflow(_)) |
142 InterpError::TypeckError => return Err(ErrorHandled::Reported),
145 trace!("reporting const eval failure at {:?}", self.span);
146 let mut err = if let Some(lint_root) = lint_root {
147 let hir_id = self.stacktrace
150 .filter_map(|frame| frame.lint_root)
152 .unwrap_or(lint_root);
153 tcx.struct_span_lint_hir(
154 crate::rustc::lint::builtin::CONST_ERR,
160 struct_error(tcx, message)
162 err.span_label(self.span, self.error.to_string());
163 // Skip the last, which is just the environment of the constant. The stacktrace
164 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
165 // on constant values.
166 if self.stacktrace.len() > 0 {
167 for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
168 err.span_label(frame_info.call_site, frame_info.to_string());
175 pub fn struct_error<'a, 'gcx, 'tcx>(
176 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
178 ) -> DiagnosticBuilder<'tcx> {
179 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
182 /// Packages the kind of error we got from the const code interpreter
183 /// up with a Rust-level backtrace of where the error occured.
184 /// Thsese should always be constructed by calling `.into()` on
185 /// a `InterpError`. In `librustc_mir::interpret`, we have the `err!`
187 #[derive(Debug, Clone)]
188 pub struct InterpErrorInfo<'tcx> {
189 pub kind: InterpError<'tcx, u64>,
190 backtrace: Option<Box<Backtrace>>,
193 impl<'tcx> InterpErrorInfo<'tcx> {
194 pub fn print_backtrace(&mut self) {
195 if let Some(ref mut backtrace) = self.backtrace {
196 print_backtrace(&mut *backtrace);
201 fn print_backtrace(backtrace: &mut Backtrace) {
203 eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
206 impl<'tcx> From<InterpError<'tcx, u64>> for InterpErrorInfo<'tcx> {
207 fn from(kind: InterpError<'tcx, u64>) -> Self {
208 let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
209 // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
210 Ok(ref val) if val != "0" => {
211 let mut backtrace = Backtrace::new_unresolved();
213 if val == "immediate" {
215 print_backtrace(&mut backtrace);
218 Some(Box::new(backtrace))
230 pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
232 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
233 pub enum InterpError<'tcx, O> {
234 /// This variant is used by machines to signal their own errors that do not
235 /// match an existing variant.
236 MachineError(String),
238 /// Not actually an interpreter error -- used to signal that execution has exited
239 /// with the given status code. Used by Miri, but not by CTFE.
242 FunctionAbiMismatch(Abi, Abi),
243 FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
244 FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
245 FunctionArgCountMismatch,
247 UnterminatedCString(Pointer),
248 DanglingPointerDeref,
251 InvalidFunctionPointer,
253 InvalidDiscriminant(ScalarMaybeUndef),
256 msg: CheckInAllocMsg,
257 allocation_size: Size,
259 InvalidNullPointerUsage,
264 ReadUndefBytes(Size),
266 InvalidBoolOp(mir::BinOp),
267 Unimplemented(String),
268 DerefFunctionPointer,
270 BoundsCheck { len: O, index: O },
271 Overflow(mir::BinOp),
277 StackFrameLimitReached,
280 AbiViolation(String),
281 AlignmentCheckFailed {
285 ValidationFailure(String),
286 CalledClosureAsFunction,
287 VtableForArgumentlessMethod,
288 ModifiedConstantMemory,
292 TypeNotPrimitive(Ty<'tcx>),
293 ReallocatedWrongMemoryKind(String, String),
294 DeallocatedWrongMemoryKind(String, String),
295 ReallocateNonBasePtr,
296 DeallocateNonBasePtr,
297 IncorrectAllocationInformation(Size, Size, Align, Align),
298 Layout(layout::LayoutError<'tcx>),
300 HeapAllocNonPowerOfTwoAlignment(u64),
308 ReadFromReturnPointer,
309 PathNotFound(Vec<String>),
310 UnimplementedTraitSelection,
311 /// Abort in case type errors are reached
313 /// Resolution can fail if we are in a too generic context
315 /// Cannot compute this constant because it depends on another one
316 /// which already produced an error
318 GeneratorResumedAfterReturn,
319 GeneratorResumedAfterPanic,
323 pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
325 impl<'tcx, O> InterpError<'tcx, O> {
326 pub fn description(&self) -> &str {
327 use self::InterpError::*;
329 MachineError(ref inner) => inner,
332 FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
333 | FunctionArgCountMismatch =>
334 "tried to call a function through a function pointer of incompatible type",
335 InvalidMemoryAccess =>
336 "tried to access memory through an invalid pointer",
337 DanglingPointerDeref =>
338 "dangling pointer was dereferenced",
340 "tried to deallocate dangling pointer",
341 InvalidFunctionPointer =>
342 "tried to use a function pointer after offsetting it",
344 "invalid boolean value read",
345 InvalidDiscriminant(..) =>
346 "invalid enum discriminant value read",
347 PointerOutOfBounds { .. } =>
348 "pointer offset outside bounds of allocation",
349 InvalidNullPointerUsage =>
350 "invalid use of NULL pointer",
351 ValidationFailure(..) =>
352 "type validation failed",
353 ReadPointerAsBytes =>
354 "a raw memory access tried to access part of a pointer value as raw bytes",
355 ReadBytesAsPointer =>
356 "a memory access tried to interpret some bytes as a pointer",
358 "tried to read from foreign (extern) static",
359 InvalidPointerMath =>
360 "attempted to do invalid arithmetic on pointers that would leak base addresses, \
361 e.g., comparing pointers into different allocations",
363 "attempted to read undefined bytes",
365 "tried to access a dead local variable",
367 "invalid boolean operation",
368 Unimplemented(ref msg) => msg,
369 DerefFunctionPointer =>
370 "tried to dereference a function pointer",
372 "tried to treat a memory pointer as a function pointer",
374 "array index out of bounds",
380 "tried to interpret an invalid 32-bit value as a char",
381 StackFrameLimitReached =>
382 "reached the configured maximum number of stack frames",
384 "reached the maximum number of representable TLS keys",
386 "accessed an invalid (unallocated) TLS key",
387 AbiViolation(ref msg) => msg,
388 AlignmentCheckFailed{..} =>
389 "tried to execute a misaligned read or write",
390 CalledClosureAsFunction =>
391 "tried to call a closure through a function pointer",
392 VtableForArgumentlessMethod =>
393 "tried to call a vtable function without arguments",
394 ModifiedConstantMemory =>
395 "tried to modify constant memory",
397 "tried to modify a static's initial value from another static's initializer",
399 "`assume` argument was false",
401 "miri does not support inline assembly",
402 TypeNotPrimitive(_) =>
403 "expected primitive type, got nonprimitive",
404 ReallocatedWrongMemoryKind(_, _) =>
405 "tried to reallocate memory from one kind to another",
406 DeallocatedWrongMemoryKind(_, _) =>
407 "tried to deallocate memory of the wrong kind",
408 ReallocateNonBasePtr =>
409 "tried to reallocate with a pointer not to the beginning of an existing object",
410 DeallocateNonBasePtr =>
411 "tried to deallocate with a pointer not to the beginning of an existing object",
412 IncorrectAllocationInformation(..) =>
413 "tried to deallocate or reallocate using incorrect alignment or size",
415 "rustc layout computation failed",
416 UnterminatedCString(_) =>
417 "attempted to get length of a null terminated string, but no null found before end \
419 HeapAllocZeroBytes =>
420 "tried to re-, de- or allocate zero bytes on the heap",
421 HeapAllocNonPowerOfTwoAlignment(_) =>
422 "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
425 "entered unreachable code",
427 "the evaluated program panicked",
428 ReadFromReturnPointer =>
429 "tried to read from the return pointer",
431 "a path could not be resolved, maybe the crate is not loaded",
432 UnimplementedTraitSelection =>
433 "there were unresolved type arguments during trait selection",
435 "encountered constants with type errors, stopping evaluation",
437 "encountered overly generic constant",
438 ReferencedConstant =>
439 "referenced constant has errors",
440 Overflow(mir::BinOp::Add) => "attempt to add with overflow",
441 Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
442 Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
443 Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
444 Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
445 OverflowNeg => "attempt to negate with overflow",
446 Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
447 Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
448 Overflow(op) => bug!("{:?} cannot overflow", op),
449 DivisionByZero => "attempt to divide by zero",
450 RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
451 GeneratorResumedAfterReturn => "generator resumed after completion",
452 GeneratorResumedAfterPanic => "generator resumed after panicking",
454 "duplicate interpreter state observed here, const evaluation will never terminate",
459 impl<'tcx> fmt::Display for InterpErrorInfo<'tcx> {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 write!(f, "{}", self.kind)
465 impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
466 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467 write!(f, "{:?}", self)
471 impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473 use self::InterpError::*;
475 PointerOutOfBounds { ptr, msg, allocation_size } => {
476 write!(f, "{} failed: pointer must be in-bounds at offset {}, \
477 but is outside bounds of allocation {} which has size {}",
478 msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
480 ValidationFailure(ref err) => {
481 write!(f, "type validation failed: {}", err)
483 NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
484 FunctionAbiMismatch(caller_abi, callee_abi) =>
485 write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
486 callee_abi, caller_abi),
487 FunctionArgMismatch(caller_ty, callee_ty) =>
488 write!(f, "tried to call a function with argument of type {:?} \
489 passing data of type {:?}",
490 callee_ty, caller_ty),
491 FunctionRetMismatch(caller_ty, callee_ty) =>
492 write!(f, "tried to call a function with return type {:?} \
493 passing return place of type {:?}",
494 callee_ty, caller_ty),
495 FunctionArgCountMismatch =>
496 write!(f, "tried to call a function with incorrect number of arguments"),
497 BoundsCheck { ref len, ref index } =>
498 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
499 ReallocatedWrongMemoryKind(ref old, ref new) =>
500 write!(f, "tried to reallocate memory from {} to {}", old, new),
501 DeallocatedWrongMemoryKind(ref old, ref new) =>
502 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
503 Intrinsic(ref err) =>
504 write!(f, "{}", err),
506 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
507 AlignmentCheckFailed { required, has } =>
508 write!(f, "tried to access memory with alignment {}, but alignment {} is required",
509 has.bytes(), required.bytes()),
510 TypeNotPrimitive(ty) =>
511 write!(f, "expected primitive type, got {}", ty),
513 write!(f, "rustc layout computation failed: {:?}", err),
514 PathNotFound(ref path) =>
515 write!(f, "Cannot find path {:?}", path),
516 MachineError(ref inner) =>
517 write!(f, "{}", inner),
518 IncorrectAllocationInformation(size, size2, align, align2) =>
519 write!(f, "incorrect alloc info: expected size {} and align {}, \
520 got size {} and align {}",
521 size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
522 Panic { ref msg, line, col, ref file } =>
523 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
524 InvalidDiscriminant(val) =>
525 write!(f, "encountered invalid enum discriminant {}", val),
527 write!(f, "exited with status code {}", code),
528 _ => write!(f, "{}", self.description()),