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, RustcEncodable, RustcDecodable)]
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 CloneTypeFoldableImpls! {
44 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
45 pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
47 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
48 pub struct ConstEvalErr<'tcx> {
50 pub error: crate::mir::interpret::InterpError<'tcx, u64>,
51 pub stacktrace: Vec<FrameInfo<'tcx>>,
54 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
55 pub struct FrameInfo<'tcx> {
56 /// This span is in the caller.
58 pub instance: ty::Instance<'tcx>,
59 pub lint_root: Option<hir::HirId>,
62 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 if tcx.def_key(self.instance.def_id()).disambiguated_data.data
66 == DefPathData::ClosureExpr
68 write!(f, "inside call to closure")?;
70 write!(f, "inside call to `{}`", self.instance)?;
72 if !self.call_site.is_dummy() {
73 let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo());
74 write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
81 impl<'tcx> ConstEvalErr<'tcx> {
86 ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
87 self.struct_generic(tcx, message, None)
90 pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
91 let err = self.struct_error(tcx, message);
95 ErrorHandled::Reported
101 pub fn report_as_lint(
105 lint_root: hir::HirId,
108 let lint = self.struct_generic(
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, "");
128 ErrorHandled::Reported
138 lint_root: Option<hir::HirId>,
139 ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
141 InterpError::Layout(LayoutError::Unknown(_)) |
142 InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric),
143 InterpError::Layout(LayoutError::SizeOverflow(_)) |
144 InterpError::TypeckError => return Err(ErrorHandled::Reported),
147 trace!("reporting const eval failure at {:?}", self.span);
148 let mut err = if let Some(lint_root) = lint_root {
149 let hir_id = self.stacktrace
152 .filter_map(|frame| frame.lint_root)
154 .unwrap_or(lint_root);
155 tcx.struct_span_lint_hir(
156 crate::rustc::lint::builtin::CONST_ERR,
162 struct_error(tcx, message)
164 err.span_label(self.span, self.error.to_string());
165 // Skip the last, which is just the environment of the constant. The stacktrace
166 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
167 // on constant values.
168 if self.stacktrace.len() > 0 {
169 for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
170 err.span_label(frame_info.call_site, frame_info.to_string());
177 pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
178 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
181 /// Packages the kind of error we got from the const code interpreter
182 /// up with a Rust-level backtrace of where the error occured.
183 /// Thsese should always be constructed by calling `.into()` on
184 /// a `InterpError`. In `librustc_mir::interpret`, we have the `err!`
186 #[derive(Debug, Clone)]
187 pub struct InterpErrorInfo<'tcx> {
188 pub kind: InterpError<'tcx, u64>,
189 backtrace: Option<Box<Backtrace>>,
192 impl<'tcx> InterpErrorInfo<'tcx> {
193 pub fn print_backtrace(&mut self) {
194 if let Some(ref mut backtrace) = self.backtrace {
195 print_backtrace(&mut *backtrace);
200 fn print_backtrace(backtrace: &mut Backtrace) {
202 eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
205 impl<'tcx> From<InterpError<'tcx, u64>> for InterpErrorInfo<'tcx> {
206 fn from(kind: InterpError<'tcx, u64>) -> Self {
207 let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
208 // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
209 Ok(ref val) if val != "0" => {
210 let mut backtrace = Backtrace::new_unresolved();
212 if val == "immediate" {
214 print_backtrace(&mut backtrace);
217 Some(Box::new(backtrace))
229 pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
231 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
232 pub enum PanicMessage<O> {
243 Overflow(mir::BinOp),
249 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
250 pub enum InterpError<'tcx, O> {
251 /// This variant is used by machines to signal their own errors that do not
252 /// match an existing variant.
253 MachineError(String),
255 /// Not actually an interpreter error -- used to signal that execution has exited
256 /// with the given status code. Used by Miri, but not by CTFE.
259 FunctionAbiMismatch(Abi, Abi),
260 FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
261 FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
262 FunctionArgCountMismatch,
264 UnterminatedCString(Pointer),
265 DanglingPointerDeref,
268 InvalidFunctionPointer,
270 InvalidDiscriminant(ScalarMaybeUndef),
273 msg: CheckInAllocMsg,
274 allocation_size: Size,
276 InvalidNullPointerUsage,
281 ReadUndefBytes(Size),
283 InvalidBoolOp(mir::BinOp),
284 Unimplemented(String),
285 DerefFunctionPointer,
289 StackFrameLimitReached,
292 AbiViolation(String),
293 AlignmentCheckFailed {
297 ValidationFailure(String),
298 CalledClosureAsFunction,
299 VtableForArgumentlessMethod,
300 ModifiedConstantMemory,
304 TypeNotPrimitive(Ty<'tcx>),
305 ReallocatedWrongMemoryKind(String, String),
306 DeallocatedWrongMemoryKind(String, String),
307 ReallocateNonBasePtr,
308 DeallocateNonBasePtr,
309 IncorrectAllocationInformation(Size, Size, Align, Align),
310 Layout(layout::LayoutError<'tcx>),
312 HeapAllocNonPowerOfTwoAlignment(u64),
314 Panic(PanicMessage<O>),
315 ReadFromReturnPointer,
316 PathNotFound(Vec<String>),
317 UnimplementedTraitSelection,
318 /// Abort in case type errors are reached
320 /// Resolution can fail if we are in a too generic context
322 /// Cannot compute this constant because it depends on another one
323 /// which already produced an error
325 GeneratorResumedAfterReturn,
326 GeneratorResumedAfterPanic,
330 pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
332 impl<'tcx, O> InterpError<'tcx, O> {
333 pub fn description(&self) -> &str {
334 use self::InterpError::*;
336 MachineError(ref inner) => inner,
339 FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
340 | FunctionArgCountMismatch =>
341 "tried to call a function through a function pointer of incompatible type",
342 InvalidMemoryAccess =>
343 "tried to access memory through an invalid pointer",
344 DanglingPointerDeref =>
345 "dangling pointer was dereferenced",
347 "tried to deallocate dangling pointer",
348 InvalidFunctionPointer =>
349 "tried to use a function pointer after offsetting it",
351 "invalid boolean value read",
352 InvalidDiscriminant(..) =>
353 "invalid enum discriminant value read",
354 PointerOutOfBounds { .. } =>
355 "pointer offset outside bounds of allocation",
356 InvalidNullPointerUsage =>
357 "invalid use of NULL pointer",
358 ValidationFailure(..) =>
359 "type validation failed",
360 ReadPointerAsBytes =>
361 "a raw memory access tried to access part of a pointer value as raw bytes",
362 ReadBytesAsPointer =>
363 "a memory access tried to interpret some bytes as a pointer",
365 "tried to read from foreign (extern) static",
366 InvalidPointerMath =>
367 "attempted to do invalid arithmetic on pointers that would leak base addresses, \
368 e.g., comparing pointers into different allocations",
370 "attempted to read undefined bytes",
372 "tried to access a dead local variable",
374 "invalid boolean operation",
375 Unimplemented(ref msg) => msg,
376 DerefFunctionPointer =>
377 "tried to dereference a function pointer",
379 "tried to treat a memory pointer as a function pointer",
385 "tried to interpret an invalid 32-bit value as a char",
386 StackFrameLimitReached =>
387 "reached the configured maximum number of stack frames",
389 "reached the maximum number of representable TLS keys",
391 "accessed an invalid (unallocated) TLS key",
392 AbiViolation(ref msg) => msg,
393 AlignmentCheckFailed{..} =>
394 "tried to execute a misaligned read or write",
395 CalledClosureAsFunction =>
396 "tried to call a closure through a function pointer",
397 VtableForArgumentlessMethod =>
398 "tried to call a vtable function without arguments",
399 ModifiedConstantMemory =>
400 "tried to modify constant memory",
402 "tried to modify a static's initial value from another static's initializer",
404 "`assume` argument was false",
406 "miri does not support inline assembly",
407 TypeNotPrimitive(_) =>
408 "expected primitive type, got nonprimitive",
409 ReallocatedWrongMemoryKind(_, _) =>
410 "tried to reallocate memory from one kind to another",
411 DeallocatedWrongMemoryKind(_, _) =>
412 "tried to deallocate memory of the wrong kind",
413 ReallocateNonBasePtr =>
414 "tried to reallocate with a pointer not to the beginning of an existing object",
415 DeallocateNonBasePtr =>
416 "tried to deallocate with a pointer not to the beginning of an existing object",
417 IncorrectAllocationInformation(..) =>
418 "tried to deallocate or reallocate using incorrect alignment or size",
420 "rustc layout computation failed",
421 UnterminatedCString(_) =>
422 "attempted to get length of a null terminated string, but no null found before end \
424 HeapAllocZeroBytes =>
425 "tried to re-, de- or allocate zero bytes on the heap",
426 HeapAllocNonPowerOfTwoAlignment(_) =>
427 "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
430 "entered unreachable code",
431 Panic(PanicMessage::Panic{..}) =>
432 "the evaluated program panicked",
433 Panic(PanicMessage::BoundsCheck{..}) =>
434 "array index out of bounds",
435 Panic(PanicMessage::Overflow(mir::BinOp::Add)) =>
436 "attempt to add with overflow",
437 Panic(PanicMessage::Overflow(mir::BinOp::Sub)) =>
438 "attempt to subtract with overflow",
439 Panic(PanicMessage::Overflow(mir::BinOp::Mul)) =>
440 "attempt to multiply with overflow",
441 Panic(PanicMessage::Overflow(mir::BinOp::Div)) =>
442 "attempt to divide with overflow",
443 Panic(PanicMessage::Overflow(mir::BinOp::Rem)) =>
444 "attempt to calculate the remainder with overflow",
445 Panic(PanicMessage::OverflowNeg) =>
446 "attempt to negate with overflow",
447 Panic(PanicMessage::Overflow(mir::BinOp::Shr)) =>
448 "attempt to shift right with overflow",
449 Panic(PanicMessage::Overflow(mir::BinOp::Shl)) =>
450 "attempt to shift left with overflow",
451 Panic(PanicMessage::Overflow(op)) =>
452 bug!("{:?} cannot overflow", op),
453 Panic(PanicMessage::DivisionByZero) =>
454 "attempt to divide by zero",
455 Panic(PanicMessage::RemainderByZero) =>
456 "attempt to calculate the remainder with a divisor of zero",
457 ReadFromReturnPointer =>
458 "tried to read from the return pointer",
460 "a path could not be resolved, maybe the crate is not loaded",
461 UnimplementedTraitSelection =>
462 "there were unresolved type arguments during trait selection",
464 "encountered constants with type errors, stopping evaluation",
466 "encountered overly generic constant",
467 ReferencedConstant =>
468 "referenced constant has errors",
469 GeneratorResumedAfterReturn => "generator resumed after completion",
470 GeneratorResumedAfterPanic => "generator resumed after panicking",
472 "duplicate interpreter state observed here, const evaluation will never terminate",
477 impl<'tcx> fmt::Display for InterpErrorInfo<'tcx> {
478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479 write!(f, "{}", self.kind)
483 impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 write!(f, "{:?}", self)
489 impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
490 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
491 use self::InterpError::*;
493 PointerOutOfBounds { ptr, msg, allocation_size } => {
494 write!(f, "{} failed: pointer must be in-bounds at offset {}, \
495 but is outside bounds of allocation {} which has size {}",
496 msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
498 ValidationFailure(ref err) => {
499 write!(f, "type validation failed: {}", err)
501 NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
502 FunctionAbiMismatch(caller_abi, callee_abi) =>
503 write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
504 callee_abi, caller_abi),
505 FunctionArgMismatch(caller_ty, callee_ty) =>
506 write!(f, "tried to call a function with argument of type {:?} \
507 passing data of type {:?}",
508 callee_ty, caller_ty),
509 FunctionRetMismatch(caller_ty, callee_ty) =>
510 write!(f, "tried to call a function with return type {:?} \
511 passing return place of type {:?}",
512 callee_ty, caller_ty),
513 FunctionArgCountMismatch =>
514 write!(f, "tried to call a function with incorrect number of arguments"),
515 ReallocatedWrongMemoryKind(ref old, ref new) =>
516 write!(f, "tried to reallocate memory from {} to {}", old, new),
517 DeallocatedWrongMemoryKind(ref old, ref new) =>
518 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
519 Intrinsic(ref err) =>
520 write!(f, "{}", err),
522 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
523 AlignmentCheckFailed { required, has } =>
524 write!(f, "tried to access memory with alignment {}, but alignment {} is required",
525 has.bytes(), required.bytes()),
526 TypeNotPrimitive(ty) =>
527 write!(f, "expected primitive type, got {}", ty),
529 write!(f, "rustc layout computation failed: {:?}", err),
530 PathNotFound(ref path) =>
531 write!(f, "Cannot find path {:?}", path),
532 MachineError(ref inner) =>
533 write!(f, "{}", inner),
534 IncorrectAllocationInformation(size, size2, align, align2) =>
535 write!(f, "incorrect alloc info: expected size {} and align {}, \
536 got size {} and align {}",
537 size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
538 Panic(PanicMessage::Panic { ref msg, line, col, ref file }) =>
539 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
540 Panic(PanicMessage::BoundsCheck { ref len, ref index }) =>
541 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
542 InvalidDiscriminant(val) =>
543 write!(f, "encountered invalid enum discriminant {}", val),
545 write!(f, "exited with status code {}", code),
546 _ => write!(f, "{}", self.description()),