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>,
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 err_inval!(Layout(LayoutError::Unknown(_))) |
142 err_inval!(TooGeneric) =>
143 return Err(ErrorHandled::TooGeneric),
144 err_inval!(Layout(LayoutError::SizeOverflow(_))) |
145 err_inval!(TypeckError) =>
146 return Err(ErrorHandled::Reported),
149 trace!("reporting const eval failure at {:?}", self.span);
150 let mut err = if let Some(lint_root) = lint_root {
151 let hir_id = self.stacktrace
154 .filter_map(|frame| frame.lint_root)
156 .unwrap_or(lint_root);
157 tcx.struct_span_lint_hir(
158 crate::rustc::lint::builtin::CONST_ERR,
164 struct_error(tcx, message)
166 err.span_label(self.span, self.error.to_string());
167 // Skip the last, which is just the environment of the constant. The stacktrace
168 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
169 // on constant values.
170 if self.stacktrace.len() > 0 {
171 for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
172 err.span_label(frame_info.call_site, frame_info.to_string());
179 pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
180 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
183 /// Packages the kind of error we got from the const code interpreter
184 /// up with a Rust-level backtrace of where the error occured.
185 /// Thsese should always be constructed by calling `.into()` on
186 /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
188 #[derive(Debug, Clone)]
189 pub struct InterpErrorInfo<'tcx> {
190 pub kind: InterpError<'tcx>,
191 backtrace: Option<Box<Backtrace>>,
195 impl fmt::Display for InterpErrorInfo<'_> {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 write!(f, "{}", self.kind)
201 impl InterpErrorInfo<'_> {
202 pub fn print_backtrace(&mut self) {
203 if let Some(ref mut backtrace) = self.backtrace {
204 print_backtrace(&mut *backtrace);
209 fn print_backtrace(backtrace: &mut Backtrace) {
211 eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
214 impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
215 fn from(kind: InterpError<'tcx>) -> Self {
216 let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
217 // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
218 Ok(ref val) if val != "0" => {
219 let mut backtrace = Backtrace::new_unresolved();
221 if val == "immediate" {
223 print_backtrace(&mut backtrace);
226 Some(Box::new(backtrace))
238 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
239 pub enum PanicInfo<O> {
250 Overflow(mir::BinOp),
254 GeneratorResumedAfterReturn,
255 GeneratorResumedAfterPanic,
258 /// Type for MIR `Assert` terminator error messages.
259 pub type AssertMessage<'tcx> = PanicInfo<mir::Operand<'tcx>>;
261 impl<O> PanicInfo<O> {
262 /// Getting a description does not require `O` to be printable, and does not
263 /// require allocation.
264 /// The caller is expected to handle `Panic` and `BoundsCheck` separately.
265 pub fn description(&self) -> &'static str {
268 Overflow(mir::BinOp::Add) =>
269 "attempt to add with overflow",
270 Overflow(mir::BinOp::Sub) =>
271 "attempt to subtract with overflow",
272 Overflow(mir::BinOp::Mul) =>
273 "attempt to multiply with overflow",
274 Overflow(mir::BinOp::Div) =>
275 "attempt to divide with overflow",
276 Overflow(mir::BinOp::Rem) =>
277 "attempt to calculate the remainder with overflow",
279 "attempt to negate with overflow",
280 Overflow(mir::BinOp::Shr) =>
281 "attempt to shift right with overflow",
282 Overflow(mir::BinOp::Shl) =>
283 "attempt to shift left with overflow",
285 bug!("{:?} cannot overflow", op),
287 "attempt to divide by zero",
289 "attempt to calculate the remainder with a divisor of zero",
290 GeneratorResumedAfterReturn =>
291 "generator resumed after completion",
292 GeneratorResumedAfterPanic =>
293 "generator resumed after panicking",
294 Panic { .. } | BoundsCheck { .. } =>
295 bug!("Unexpected PanicInfo"),
300 impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 Panic { ref msg, line, col, ref file } =>
305 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
306 BoundsCheck { ref len, ref index } =>
307 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
309 write!(f, "{}", self.description()),
314 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
315 pub enum InvalidProgramInfo<'tcx> {
316 /// Resolution can fail if we are in a too generic context.
318 /// Cannot compute this constant because it depends on another one
319 /// which already produced an error.
321 /// Abort in case type errors are reached.
323 /// An error occurred during layout computation.
324 Layout(layout::LayoutError<'tcx>),
327 impl fmt::Debug for InvalidProgramInfo<'tcx> {
328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 use InvalidProgramInfo::*;
332 write!(f, "encountered overly generic constant"),
333 ReferencedConstant =>
334 write!(f, "referenced constant has errors"),
336 write!(f, "encountered constants with type errors, stopping evaluation"),
338 write!(f, "rustc layout computation failed: {:?}", err),
343 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
344 pub enum UndefinedBehaviourInfo {
345 /// Handle cases which for which we do not have a fixed variant.
347 /// Unreachable code was executed.
351 impl fmt::Debug for UndefinedBehaviourInfo {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 use UndefinedBehaviourInfo::*;
356 write!(f, "{}", msg),
358 write!(f, "entered unreachable code"),
363 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
364 pub enum UnsupportedOpInfo<'tcx> {
365 /// Handle cases which for which we do not have a fixed variant.
366 Unimplemented(String),
368 // -- Everything below is not classified yet --
369 FunctionAbiMismatch(Abi, Abi),
370 FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
371 FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
372 FunctionArgCountMismatch,
373 UnterminatedCString(Pointer),
374 DanglingPointerDeref,
377 InvalidFunctionPointer,
379 InvalidDiscriminant(ScalarMaybeUndef),
382 msg: CheckInAllocMsg,
383 allocation_size: Size,
385 InvalidNullPointerUsage,
390 ReadUndefBytes(Size),
392 InvalidBoolOp(mir::BinOp),
394 UnimplementedTraitSelection,
395 CalledClosureAsFunction,
397 /// This variant is used by machines to signal their own errors that do not
398 /// match an existing variant.
399 MachineError(String),
400 DerefFunctionPointer,
406 AbiViolation(String),
407 AlignmentCheckFailed {
411 ValidationFailure(String),
412 VtableForArgumentlessMethod,
413 ModifiedConstantMemory,
416 TypeNotPrimitive(Ty<'tcx>),
417 ReallocatedWrongMemoryKind(String, String),
418 DeallocatedWrongMemoryKind(String, String),
419 ReallocateNonBasePtr,
420 DeallocateNonBasePtr,
421 IncorrectAllocationInformation(Size, Size, Align, Align),
423 HeapAllocNonPowerOfTwoAlignment(u64),
424 ReadFromReturnPointer,
425 PathNotFound(Vec<String>),
428 impl fmt::Debug for UnsupportedOpInfo<'tcx> {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 use UnsupportedOpInfo::*;
432 PointerOutOfBounds { ptr, msg, allocation_size } => {
433 write!(f, "{} failed: pointer must be in-bounds at offset {}, \
434 but is outside bounds of allocation {} which has size {}",
435 msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
437 ValidationFailure(ref err) => {
438 write!(f, "type validation failed: {}", err)
440 NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
441 FunctionAbiMismatch(caller_abi, callee_abi) =>
442 write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
443 callee_abi, caller_abi),
444 FunctionArgMismatch(caller_ty, callee_ty) =>
445 write!(f, "tried to call a function with argument of type {:?} \
446 passing data of type {:?}",
447 callee_ty, caller_ty),
448 FunctionRetMismatch(caller_ty, callee_ty) =>
449 write!(f, "tried to call a function with return type {:?} \
450 passing return place of type {:?}",
451 callee_ty, caller_ty),
452 FunctionArgCountMismatch =>
453 write!(f, "tried to call a function with incorrect number of arguments"),
454 ReallocatedWrongMemoryKind(ref old, ref new) =>
455 write!(f, "tried to reallocate memory from {} to {}", old, new),
456 DeallocatedWrongMemoryKind(ref old, ref new) =>
457 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
459 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
460 AlignmentCheckFailed { required, has } =>
461 write!(f, "tried to access memory with alignment {}, but alignment {} is required",
462 has.bytes(), required.bytes()),
463 TypeNotPrimitive(ty) =>
464 write!(f, "expected primitive type, got {}", ty),
465 PathNotFound(ref path) =>
466 write!(f, "Cannot find path {:?}", path),
467 IncorrectAllocationInformation(size, size2, align, align2) =>
468 write!(f, "incorrect alloc info: expected size {} and align {}, \
469 got size {} and align {}",
470 size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
471 InvalidDiscriminant(val) =>
472 write!(f, "encountered invalid enum discriminant {}", val),
473 InvalidMemoryAccess =>
474 write!(f, "tried to access memory through an invalid pointer"),
475 DanglingPointerDeref =>
476 write!(f, "dangling pointer was dereferenced"),
478 write!(f, "tried to deallocate dangling pointer"),
479 InvalidFunctionPointer =>
480 write!(f, "tried to use a function pointer after offsetting it"),
482 write!(f, "invalid boolean value read"),
483 InvalidNullPointerUsage =>
484 write!(f, "invalid use of NULL pointer"),
485 ReadPointerAsBytes =>
486 write!(f, "a raw memory access tried to access part of a pointer value as raw \
488 ReadBytesAsPointer =>
489 write!(f, "a memory access tried to interpret some bytes as a pointer"),
491 write!(f, "tried to read from foreign (extern) static"),
492 InvalidPointerMath =>
493 write!(f, "attempted to do invalid arithmetic on pointers that would leak base \
494 addresses, e.g., comparing pointers into different allocations"),
496 write!(f, "tried to access a dead local variable"),
497 DerefFunctionPointer =>
498 write!(f, "tried to dereference a function pointer"),
500 write!(f, "tried to treat a memory pointer as a function pointer"),
502 write!(f, "reached the maximum number of representable TLS keys"),
504 write!(f, "accessed an invalid (unallocated) TLS key"),
505 CalledClosureAsFunction =>
506 write!(f, "tried to call a closure through a function pointer"),
507 VtableForArgumentlessMethod =>
508 write!(f, "tried to call a vtable function without arguments"),
509 ModifiedConstantMemory =>
510 write!(f, "tried to modify constant memory"),
512 write!(f, "tried to modify a static's initial value from another static's \
515 write!(f, "`assume` argument was false"),
517 write!(f, "miri does not support inline assembly"),
518 ReallocateNonBasePtr =>
519 write!(f, "tried to reallocate with a pointer not to the beginning of an \
521 DeallocateNonBasePtr =>
522 write!(f, "tried to deallocate with a pointer not to the beginning of an \
524 HeapAllocZeroBytes =>
525 write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
526 ReadFromReturnPointer =>
527 write!(f, "tried to read from the return pointer"),
528 UnimplementedTraitSelection =>
529 write!(f, "there were unresolved type arguments during trait selection"),
531 write!(f, "invalid boolean operation"),
532 UnterminatedCString(_) =>
533 write!(f, "attempted to get length of a null terminated string, but no null \
534 found before end of allocation"),
536 write!(f, "attempted to read undefined bytes"),
537 HeapAllocNonPowerOfTwoAlignment(_) =>
538 write!(f, "tried to re-, de-, or allocate heap memory with alignment that is \
539 not a power of two"),
540 MachineError(ref msg) |
541 Unimplemented(ref msg) |
542 AbiViolation(ref msg) |
543 Intrinsic(ref msg) =>
544 write!(f, "{}", msg),
549 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
550 pub enum ResourceExhaustionInfo {
551 /// The stack grew too big.
552 StackFrameLimitReached,
553 /// The program ran into an infinite loop.
557 impl fmt::Debug for ResourceExhaustionInfo {
558 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559 use ResourceExhaustionInfo::*;
561 StackFrameLimitReached =>
562 write!(f, "reached the configured maximum number of stack frames"),
564 write!(f, "duplicate interpreter state observed here, const evaluation will never \
570 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
571 pub enum InterpError<'tcx> {
572 /// The program panicked.
573 Panic(PanicInfo<u64>),
574 /// The program caused undefined behavior.
575 UndefinedBehaviour(UndefinedBehaviourInfo),
576 /// The program did something the interpreter does not support (some of these *might* be UB
577 /// but the interpreter is not sure).
578 Unsupported(UnsupportedOpInfo<'tcx>),
579 /// The program was invalid (ill-typed, not sufficiently monomorphized, ...).
580 InvalidProgram(InvalidProgramInfo<'tcx>),
581 /// The program exhausted the interpreter's resources (stack/heap too big,
582 /// execution takes too long, ..).
583 ResourceExhaustion(ResourceExhaustionInfo),
584 /// Not actually an interpreter error -- used to signal that execution has exited
585 /// with the given status code. Used by Miri, but not by CTFE.
589 pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
591 impl fmt::Display for InterpError<'_> {
592 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
593 // Forward `Display` to `Debug`
594 write!(f, "{:?}", self)
598 impl fmt::Debug for InterpError<'_> {
599 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
602 Unsupported(ref msg) =>
603 write!(f, "{:?}", msg),
604 InvalidProgram(ref msg) =>
605 write!(f, "{:?}", msg),
606 UndefinedBehaviour(ref msg) =>
607 write!(f, "{:?}", msg),
608 ResourceExhaustion(ref msg) =>
609 write!(f, "{:?}", msg),
611 write!(f, "{:?}", msg),
613 write!(f, "exited with status code {}", code),