3 use crate::hir::map::definitions::DefPathData;
5 use crate::ty::{self, Ty, layout};
6 use crate::ty::layout::{Size, Align, LayoutError};
7 use rustc_target::spec::abi::Abi;
9 use super::{RawConst, Pointer, InboundsCheck, ScalarMaybeUndef};
11 use backtrace::Backtrace;
13 use crate::ty::query::TyCtxtAt;
14 use errors::DiagnosticBuilder;
16 use syntax_pos::{Pos, Span};
18 use syntax::symbol::Symbol;
20 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
21 pub enum ErrorHandled {
22 /// Already reported a lint or an error for this evaluation
24 /// Don't emit an error, the evaluation failed because the MIR was generic
25 /// and the substs didn't fully monomorphize it.
30 pub fn assert_reported(self) {
32 ErrorHandled::Reported => {},
33 ErrorHandled::TooGeneric => bug!("MIR interpretation failed without reporting an error \
34 even though it was fully monomorphized"),
39 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
40 pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
42 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
43 pub struct ConstEvalErr<'tcx> {
45 pub error: crate::mir::interpret::EvalErrorKind<'tcx, u64>,
46 pub stacktrace: Vec<FrameInfo<'tcx>>,
49 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
50 pub struct FrameInfo<'tcx> {
51 pub call_site: Span, // this span is in the caller!
52 pub instance: ty::Instance<'tcx>,
53 pub lint_root: Option<ast::NodeId>,
56 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 if tcx.def_key(self.instance.def_id()).disambiguated_data.data
60 == DefPathData::ClosureExpr
62 write!(f, "inside call to closure")?;
64 write!(f, "inside call to `{}`", self.instance)?;
66 if !self.call_site.is_dummy() {
67 let lo = tcx.sess.source_map().lookup_char_pos_adj(self.call_site.lo());
68 write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?;
75 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
76 pub fn struct_error(&self,
77 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
79 -> Result<DiagnosticBuilder<'tcx>, ErrorHandled>
81 self.struct_generic(tcx, message, None)
84 pub fn report_as_error(&self,
85 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
88 let err = self.struct_error(tcx, message);
92 ErrorHandled::Reported
98 pub fn report_as_lint(&self,
99 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
101 lint_root: ast::NodeId,
103 let lint = self.struct_generic(
111 ErrorHandled::Reported
119 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
121 lint_root: Option<ast::NodeId>,
122 ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
124 EvalErrorKind::Layout(LayoutError::Unknown(_)) |
125 EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
126 EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
127 EvalErrorKind::TypeckError => return Err(ErrorHandled::Reported),
130 trace!("reporting const eval failure at {:?}", self.span);
131 let mut err = if let Some(lint_root) = lint_root {
132 let node_id = self.stacktrace
135 .filter_map(|frame| frame.lint_root)
137 .unwrap_or(lint_root);
138 tcx.struct_span_lint_node(
139 crate::rustc::lint::builtin::CONST_ERR,
145 struct_error(tcx, message)
147 err.span_label(self.span, self.error.to_string());
148 // Skip the last, which is just the environment of the constant. The stacktrace
149 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
150 // on constant values.
151 if self.stacktrace.len() > 0 {
152 for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
153 err.span_label(frame_info.call_site, frame_info.to_string());
160 pub fn struct_error<'a, 'gcx, 'tcx>(
161 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
163 ) -> DiagnosticBuilder<'tcx> {
164 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
167 #[derive(Debug, Clone)]
168 pub struct EvalError<'tcx> {
169 pub kind: EvalErrorKind<'tcx, u64>,
170 pub backtrace: Option<Box<Backtrace>>,
173 impl<'tcx> EvalError<'tcx> {
174 pub fn print_backtrace(&mut self) {
175 if let Some(ref mut backtrace) = self.backtrace {
176 print_backtrace(&mut *backtrace);
181 fn print_backtrace(backtrace: &mut Backtrace) {
183 eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
186 impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
187 fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
188 let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
189 // matching RUST_BACKTRACE, we treat "0" the same as "not present".
190 Ok(ref val) if val != "0" => {
191 let mut backtrace = Backtrace::new_unresolved();
193 if val == "immediate" {
195 print_backtrace(&mut backtrace);
198 Some(Box::new(backtrace))
210 pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>;
212 #[derive(Clone, RustcEncodable, RustcDecodable)]
213 pub enum EvalErrorKind<'tcx, O> {
214 /// This variant is used by machines to signal their own errors that do not
215 /// match an existing variant
216 MachineError(String),
218 FunctionAbiMismatch(Abi, Abi),
219 FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
220 FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
221 FunctionArgCountMismatch,
223 UnterminatedCString(Pointer),
224 DanglingPointerDeref,
227 InvalidFunctionPointer,
229 InvalidDiscriminant(ScalarMaybeUndef),
232 check: InboundsCheck,
233 allocation_size: Size,
235 InvalidNullPointerUsage,
240 ReadUndefBytes(Size),
242 InvalidBoolOp(mir::BinOp),
243 Unimplemented(String),
244 DerefFunctionPointer,
246 BoundsCheck { len: O, index: O },
247 Overflow(mir::BinOp),
253 StackFrameLimitReached,
256 AbiViolation(String),
257 AlignmentCheckFailed {
261 ValidationFailure(String),
262 CalledClosureAsFunction,
263 VtableForArgumentlessMethod,
264 ModifiedConstantMemory,
268 TypeNotPrimitive(Ty<'tcx>),
269 ReallocatedWrongMemoryKind(String, String),
270 DeallocatedWrongMemoryKind(String, String),
271 ReallocateNonBasePtr,
272 DeallocateNonBasePtr,
273 IncorrectAllocationInformation(Size, Size, Align, Align),
274 Layout(layout::LayoutError<'tcx>),
276 HeapAllocNonPowerOfTwoAlignment(u64),
284 ReadFromReturnPointer,
285 PathNotFound(Vec<String>),
286 UnimplementedTraitSelection,
287 /// Abort in case type errors are reached
289 /// Resolution can fail if we are in a too generic context
291 /// Cannot compute this constant because it depends on another one
292 /// which already produced an error
294 GeneratorResumedAfterReturn,
295 GeneratorResumedAfterPanic,
299 pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
301 impl<'tcx, O> EvalErrorKind<'tcx, O> {
302 pub fn description(&self) -> &str {
303 use self::EvalErrorKind::*;
305 MachineError(ref inner) => inner,
306 FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
307 | FunctionArgCountMismatch =>
308 "tried to call a function through a function pointer of incompatible type",
309 InvalidMemoryAccess =>
310 "tried to access memory through an invalid pointer",
311 DanglingPointerDeref =>
312 "dangling pointer was dereferenced",
314 "tried to deallocate dangling pointer",
315 InvalidFunctionPointer =>
316 "tried to use a function pointer after offsetting it",
318 "invalid boolean value read",
319 InvalidDiscriminant(..) =>
320 "invalid enum discriminant value read",
321 PointerOutOfBounds { .. } =>
322 "pointer offset outside bounds of allocation",
323 InvalidNullPointerUsage =>
324 "invalid use of NULL pointer",
325 ValidationFailure(..) =>
326 "type validation failed",
327 ReadPointerAsBytes =>
328 "a raw memory access tried to access part of a pointer value as raw bytes",
329 ReadBytesAsPointer =>
330 "a memory access tried to interpret some bytes as a pointer",
332 "tried to read from foreign (extern) static",
333 InvalidPointerMath =>
334 "attempted to do invalid arithmetic on pointers that would leak base addresses, \
335 e.g., comparing pointers into different allocations",
337 "attempted to read undefined bytes",
339 "tried to access a dead local variable",
341 "invalid boolean operation",
342 Unimplemented(ref msg) => msg,
343 DerefFunctionPointer =>
344 "tried to dereference a function pointer",
346 "tried to treat a memory pointer as a function pointer",
348 "array index out of bounds",
354 "tried to interpret an invalid 32-bit value as a char",
355 StackFrameLimitReached =>
356 "reached the configured maximum number of stack frames",
358 "reached the maximum number of representable TLS keys",
360 "accessed an invalid (unallocated) TLS key",
361 AbiViolation(ref msg) => msg,
362 AlignmentCheckFailed{..} =>
363 "tried to execute a misaligned read or write",
364 CalledClosureAsFunction =>
365 "tried to call a closure through a function pointer",
366 VtableForArgumentlessMethod =>
367 "tried to call a vtable function without arguments",
368 ModifiedConstantMemory =>
369 "tried to modify constant memory",
371 "tried to modify a static's initial value from another static's initializer",
373 "`assume` argument was false",
375 "miri does not support inline assembly",
376 TypeNotPrimitive(_) =>
377 "expected primitive type, got nonprimitive",
378 ReallocatedWrongMemoryKind(_, _) =>
379 "tried to reallocate memory from one kind to another",
380 DeallocatedWrongMemoryKind(_, _) =>
381 "tried to deallocate memory of the wrong kind",
382 ReallocateNonBasePtr =>
383 "tried to reallocate with a pointer not to the beginning of an existing object",
384 DeallocateNonBasePtr =>
385 "tried to deallocate with a pointer not to the beginning of an existing object",
386 IncorrectAllocationInformation(..) =>
387 "tried to deallocate or reallocate using incorrect alignment or size",
389 "rustc layout computation failed",
390 UnterminatedCString(_) =>
391 "attempted to get length of a null terminated string, but no null found before end \
393 HeapAllocZeroBytes =>
394 "tried to re-, de- or allocate zero bytes on the heap",
395 HeapAllocNonPowerOfTwoAlignment(_) =>
396 "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
399 "entered unreachable code",
401 "the evaluated program panicked",
402 ReadFromReturnPointer =>
403 "tried to read from the return pointer",
405 "a path could not be resolved, maybe the crate is not loaded",
406 UnimplementedTraitSelection =>
407 "there were unresolved type arguments during trait selection",
409 "encountered constants with type errors, stopping evaluation",
411 "encountered overly generic constant",
412 ReferencedConstant =>
413 "referenced constant has errors",
414 Overflow(mir::BinOp::Add) => "attempt to add with overflow",
415 Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
416 Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
417 Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
418 Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
419 OverflowNeg => "attempt to negate with overflow",
420 Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
421 Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
422 Overflow(op) => bug!("{:?} cannot overflow", op),
423 DivisionByZero => "attempt to divide by zero",
424 RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
425 GeneratorResumedAfterReturn => "generator resumed after completion",
426 GeneratorResumedAfterPanic => "generator resumed after panicking",
428 "duplicate interpreter state observed here, const evaluation will never terminate",
433 impl<'tcx> fmt::Display for EvalError<'tcx> {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 write!(f, "{}", self.kind)
439 impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 write!(f, "{:?}", self)
445 impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 use self::EvalErrorKind::*;
449 PointerOutOfBounds { ptr, check, allocation_size } => {
450 write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
451 allocation {} which has size {}",
453 InboundsCheck::Live => " and live",
454 InboundsCheck::MaybeDead => "",
456 ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
458 ValidationFailure(ref err) => {
459 write!(f, "type validation failed: {}", err)
461 NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
462 FunctionAbiMismatch(caller_abi, callee_abi) =>
463 write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
464 callee_abi, caller_abi),
465 FunctionArgMismatch(caller_ty, callee_ty) =>
466 write!(f, "tried to call a function with argument of type {:?} \
467 passing data of type {:?}",
468 callee_ty, caller_ty),
469 FunctionRetMismatch(caller_ty, callee_ty) =>
470 write!(f, "tried to call a function with return type {:?} \
471 passing return place of type {:?}",
472 callee_ty, caller_ty),
473 FunctionArgCountMismatch =>
474 write!(f, "tried to call a function with incorrect number of arguments"),
475 BoundsCheck { ref len, ref index } =>
476 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
477 ReallocatedWrongMemoryKind(ref old, ref new) =>
478 write!(f, "tried to reallocate memory from {} to {}", old, new),
479 DeallocatedWrongMemoryKind(ref old, ref new) =>
480 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
481 Intrinsic(ref err) =>
482 write!(f, "{}", err),
484 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
485 AlignmentCheckFailed { required, has } =>
486 write!(f, "tried to access memory with alignment {}, but alignment {} is required",
487 has.bytes(), required.bytes()),
488 TypeNotPrimitive(ty) =>
489 write!(f, "expected primitive type, got {}", ty),
491 write!(f, "rustc layout computation failed: {:?}", err),
492 PathNotFound(ref path) =>
493 write!(f, "Cannot find path {:?}", path),
494 MachineError(ref inner) =>
495 write!(f, "{}", inner),
496 IncorrectAllocationInformation(size, size2, align, align2) =>
497 write!(f, "incorrect alloc info: expected size {} and align {}, \
498 got size {} and align {}",
499 size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
500 Panic { ref msg, line, col, ref file } =>
501 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
502 InvalidDiscriminant(val) =>
503 write!(f, "encountered invalid enum discriminant {}", val),
504 _ => write!(f, "{}", self.description()),