1 use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef}
;
4 use crate::hir
::map
::definitions
::DefPathData
;
6 use crate::ty
::{self, Ty, layout}
;
7 use crate::ty
::layout
::{Size, Align, LayoutError}
;
8 use crate::ty
::query
::TyCtxtAt
;
10 use backtrace
::Backtrace
;
11 use errors
::DiagnosticBuilder
;
12 use rustc_macros
::HashStable
;
13 use rustc_target
::spec
::abi
::Abi
;
14 use syntax_pos
::{Pos, Span}
;
15 use syntax
::symbol
::Symbol
;
16 use hir
::GeneratorKind
;
17 use std
::{fmt, env, any::Any}
;
19 use rustc_error_codes
::*;
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
>;
48 pub struct ConstEvalErr
<'tcx
> {
50 pub error
: crate::mir
::interpret
::InterpError
<'tcx
>,
51 pub stacktrace
: Vec
<FrameInfo
<'tcx
>>,
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
> {
140 let must_error
= match self.error
{
141 InterpError
::MachineStop(_
) => bug
!("CTFE does not stop"),
142 err_inval
!(Layout(LayoutError
::Unknown(_
))) |
143 err_inval
!(TooGeneric
) =>
144 return Err(ErrorHandled
::TooGeneric
),
145 err_inval
!(TypeckError
) =>
146 return Err(ErrorHandled
::Reported
),
147 err_inval
!(Layout(LayoutError
::SizeOverflow(_
))) => true,
150 trace
!("reporting const eval failure at {:?}", self.span
);
151 let mut err
= if let (Some(lint_root
), false) = (lint_root
, must_error
) {
152 let hir_id
= self.stacktrace
155 .filter_map(|frame
| frame
.lint_root
)
157 .unwrap_or(lint_root
);
158 tcx
.struct_span_lint_hir(
159 crate::rustc
::lint
::builtin
::CONST_ERR
,
164 } else if must_error
{
165 struct_error(tcx
, &self.error
.to_string())
167 struct_error(tcx
, message
)
170 err
.span_label(self.span
, self.error
.to_string());
172 // Skip the last, which is just the environment of the constant. The stacktrace
173 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
174 // on constant values.
175 if self.stacktrace
.len() > 0 {
176 for frame_info
in &self.stacktrace
[..self.stacktrace
.len()-1] {
177 err
.span_label(frame_info
.call_site
, frame_info
.to_string());
184 pub fn struct_error
<'tcx
>(tcx
: TyCtxtAt
<'tcx
>, msg
: &str) -> DiagnosticBuilder
<'tcx
> {
185 struct_span_err
!(tcx
.sess
, tcx
.span
, E0080
, "{}", msg
)
188 /// Packages the kind of error we got from the const code interpreter
189 /// up with a Rust-level backtrace of where the error occurred.
190 /// Thsese should always be constructed by calling `.into()` on
191 /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
194 pub struct InterpErrorInfo
<'tcx
> {
195 pub kind
: InterpError
<'tcx
>,
196 backtrace
: Option
<Box
<Backtrace
>>,
200 impl fmt
::Display
for InterpErrorInfo
<'_
> {
201 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
202 write
!(f
, "{}", self.kind
)
206 impl InterpErrorInfo
<'_
> {
207 pub fn print_backtrace(&mut self) {
208 if let Some(ref mut backtrace
) = self.backtrace
{
209 print_backtrace(&mut *backtrace
);
214 fn print_backtrace(backtrace
: &mut Backtrace
) {
216 eprintln
!("\n\nAn error occurred in miri:\n{:?}", backtrace
);
219 impl From
<ErrorHandled
> for InterpErrorInfo
<'tcx
> {
220 fn from(err
: ErrorHandled
) -> Self {
222 ErrorHandled
::Reported
=> err_inval
!(ReferencedConstant
),
223 ErrorHandled
::TooGeneric
=> err_inval
!(TooGeneric
),
228 impl<'tcx
> From
<InterpError
<'tcx
>> for InterpErrorInfo
<'tcx
> {
229 fn from(kind
: InterpError
<'tcx
>) -> Self {
230 let backtrace
= match env
::var("RUSTC_CTFE_BACKTRACE") {
231 // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
232 Ok(ref val
) if val
!= "0" => {
233 let mut backtrace
= Backtrace
::new_unresolved();
235 if val
== "immediate" {
237 print_backtrace(&mut backtrace
);
240 Some(Box
::new(backtrace
))
252 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
253 pub enum PanicInfo
<O
> {
264 Overflow(mir
::BinOp
),
268 ResumedAfterReturn(GeneratorKind
),
269 ResumedAfterPanic(GeneratorKind
),
272 /// Type for MIR `Assert` terminator error messages.
273 pub type AssertMessage
<'tcx
> = PanicInfo
<mir
::Operand
<'tcx
>>;
275 impl<O
> PanicInfo
<O
> {
276 /// Getting a description does not require `O` to be printable, and does not
277 /// require allocation.
278 /// The caller is expected to handle `Panic` and `BoundsCheck` separately.
279 pub fn description(&self) -> &'
static str {
282 Overflow(mir
::BinOp
::Add
) =>
283 "attempt to add with overflow",
284 Overflow(mir
::BinOp
::Sub
) =>
285 "attempt to subtract with overflow",
286 Overflow(mir
::BinOp
::Mul
) =>
287 "attempt to multiply with overflow",
288 Overflow(mir
::BinOp
::Div
) =>
289 "attempt to divide with overflow",
290 Overflow(mir
::BinOp
::Rem
) =>
291 "attempt to calculate the remainder with overflow",
293 "attempt to negate with overflow",
294 Overflow(mir
::BinOp
::Shr
) =>
295 "attempt to shift right with overflow",
296 Overflow(mir
::BinOp
::Shl
) =>
297 "attempt to shift left with overflow",
299 bug
!("{:?} cannot overflow", op
),
301 "attempt to divide by zero",
303 "attempt to calculate the remainder with a divisor of zero",
304 ResumedAfterReturn(GeneratorKind
::Gen
) =>
305 "generator resumed after completion",
306 ResumedAfterReturn(GeneratorKind
::Async(_
)) =>
307 "`async fn` resumed after completion",
308 ResumedAfterPanic(GeneratorKind
::Gen
) =>
309 "generator resumed after panicking",
310 ResumedAfterPanic(GeneratorKind
::Async(_
)) =>
311 "`async fn` resumed after panicking",
312 Panic { .. }
| BoundsCheck { .. }
=>
313 bug
!("Unexpected PanicInfo"),
318 impl<O
: fmt
::Debug
> fmt
::Debug
for PanicInfo
<O
> {
319 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
322 Panic { ref msg, line, col, ref file }
=>
323 write
!(f
, "the evaluated program panicked at '{}', {}:{}:{}", msg
, file
, line
, col
),
324 BoundsCheck { ref len, ref index }
=>
325 write
!(f
, "index out of bounds: the len is {:?} but the index is {:?}", len
, index
),
327 write
!(f
, "{}", self.description()),
332 /// Error information for when the program we executed turned out not to actually be a valid
333 /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
334 /// where we work on generic code or execution does not have all information available.
335 pub enum InvalidProgramInfo
<'tcx
> {
336 /// Resolution can fail if we are in a too generic context.
338 /// Cannot compute this constant because it depends on another one
339 /// which already produced an error.
341 /// Abort in case type errors are reached.
343 /// An error occurred during layout computation.
344 Layout(layout
::LayoutError
<'tcx
>),
347 impl fmt
::Debug
for InvalidProgramInfo
<'tcx
> {
348 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
349 use InvalidProgramInfo
::*;
352 write
!(f
, "encountered overly generic constant"),
353 ReferencedConstant
=>
354 write
!(f
, "referenced constant has errors"),
356 write
!(f
, "encountered constants with type errors, stopping evaluation"),
358 write
!(f
, "{}", err
),
363 /// Error information for when the program caused Undefined Behavior.
364 pub enum UndefinedBehaviorInfo
{
365 /// Free-form case. Only for errors that are never caught!
367 /// Free-form case for experimental UB. Only for errors that are never caught!
368 UbExperimental(String
),
369 /// Unreachable code was executed.
371 /// An enum discriminant was set to a value which was outside the range of valid values.
372 InvalidDiscriminant(ScalarMaybeUndef
),
373 /// A slice/array index projection went out-of-bounds.
374 BoundsCheckFailed { len: u64, index: u64 }
,
375 /// Something was divided by 0 (x / 0).
377 /// Something was "remainded" by 0 (x % 0).
379 /// Overflowing inbounds pointer arithmetic.
380 PointerArithOverflow
,
383 impl fmt
::Debug
for UndefinedBehaviorInfo
{
384 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
385 use UndefinedBehaviorInfo
::*;
387 Ub(msg
) | UbExperimental(msg
) =>
388 write
!(f
, "{}", msg
),
390 write
!(f
, "entering unreachable code"),
391 InvalidDiscriminant(val
) =>
392 write
!(f
, "encountering invalid enum discriminant {}", val
),
393 BoundsCheckFailed { ref len, ref index }
=>
394 write
!(f
, "indexing out of bounds: the len is {:?} but the index is {:?}",
397 write
!(f
, "dividing by zero"),
399 write
!(f
, "calculating the remainder with a divisor of zero"),
400 PointerArithOverflow
=>
401 write
!(f
, "overflowing in-bounds pointer arithmetic"),
406 /// Error information for when the program did something that might (or might not) be correct
407 /// to do according to the Rust spec, but due to limitations in the interpreter, the
408 /// operation could not be carried out. These limitations can differ between CTFE and the
409 /// Miri engine, e.g., CTFE does not support casting pointers to "real" integers.
411 /// Currently, we also use this as fall-back error kind for errors that have not been
413 pub enum UnsupportedOpInfo
<'tcx
> {
414 /// Free-form case. Only for errors that are never caught!
417 /// When const-prop encounters a situation it does not support, it raises this error.
418 /// This must not allocate for performance reasons.
419 ConstPropUnsupported(&'tcx
str),
421 // -- Everything below is not categorized yet --
422 FunctionAbiMismatch(Abi
, Abi
),
423 FunctionArgMismatch(Ty
<'tcx
>, Ty
<'tcx
>),
424 FunctionRetMismatch(Ty
<'tcx
>, Ty
<'tcx
>),
425 FunctionArgCountMismatch
,
426 UnterminatedCString(Pointer
),
427 DanglingPointerDeref
,
430 InvalidFunctionPointer
,
434 msg
: CheckInAllocMsg
,
435 allocation_size
: Size
,
437 InvalidNullPointerUsage
,
442 ReadUndefBytes(Size
),
444 InvalidBoolOp(mir
::BinOp
),
445 UnimplementedTraitSelection
,
446 CalledClosureAsFunction
,
448 DerefFunctionPointer
,
453 AlignmentCheckFailed
{
457 ValidationFailure(String
),
458 VtableForArgumentlessMethod
,
459 ModifiedConstantMemory
,
461 TypeNotPrimitive(Ty
<'tcx
>),
462 ReallocatedWrongMemoryKind(String
, String
),
463 DeallocatedWrongMemoryKind(String
, String
),
464 ReallocateNonBasePtr
,
465 DeallocateNonBasePtr
,
466 IncorrectAllocationInformation(Size
, Size
, Align
, Align
),
468 HeapAllocNonPowerOfTwoAlignment(u64),
469 ReadFromReturnPointer
,
470 PathNotFound(Vec
<String
>),
473 impl fmt
::Debug
for UnsupportedOpInfo
<'tcx
> {
474 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
475 use UnsupportedOpInfo
::*;
477 PointerOutOfBounds { ptr, msg, allocation_size }
=> {
478 write
!(f
, "{} failed: pointer must be in-bounds at offset {}, \
479 but is outside bounds of allocation {} which has size {}",
480 msg
, ptr
.offset
.bytes(), ptr
.alloc_id
, allocation_size
.bytes())
482 ValidationFailure(ref err
) => {
483 write
!(f
, "type validation failed: {}", err
)
485 NoMirFor(ref func
) => write
!(f
, "no MIR for `{}`", func
),
486 FunctionAbiMismatch(caller_abi
, callee_abi
) =>
487 write
!(f
, "tried to call a function with ABI {:?} using caller ABI {:?}",
488 callee_abi
, caller_abi
),
489 FunctionArgMismatch(caller_ty
, callee_ty
) =>
490 write
!(f
, "tried to call a function with argument of type {:?} \
491 passing data of type {:?}",
492 callee_ty
, caller_ty
),
493 FunctionRetMismatch(caller_ty
, callee_ty
) =>
494 write
!(f
, "tried to call a function with return type {:?} \
495 passing return place of type {:?}",
496 callee_ty
, caller_ty
),
497 FunctionArgCountMismatch
=>
498 write
!(f
, "tried to call a function with incorrect number of arguments"),
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
),
504 write
!(f
, "tried to interpret an invalid 32-bit value as a char: {}", c
),
505 AlignmentCheckFailed { required, has }
=>
506 write
!(f
, "tried to access memory with alignment {}, but alignment {} is required",
507 has
.bytes(), required
.bytes()),
508 TypeNotPrimitive(ty
) =>
509 write
!(f
, "expected primitive type, got {}", ty
),
510 PathNotFound(ref path
) =>
511 write
!(f
, "cannot find path {:?}", path
),
512 IncorrectAllocationInformation(size
, size2
, align
, align2
) =>
513 write
!(f
, "incorrect alloc info: expected size {} and align {}, \
514 got size {} and align {}",
515 size
.bytes(), align
.bytes(), size2
.bytes(), align2
.bytes()),
516 InvalidMemoryAccess
=>
517 write
!(f
, "tried to access memory through an invalid pointer"),
518 DanglingPointerDeref
=>
519 write
!(f
, "dangling pointer was dereferenced"),
521 write
!(f
, "tried to deallocate dangling pointer"),
522 InvalidFunctionPointer
=>
523 write
!(f
, "tried to use a function pointer after offsetting it"),
525 write
!(f
, "invalid boolean value read"),
526 InvalidNullPointerUsage
=>
527 write
!(f
, "invalid use of NULL pointer"),
528 ReadPointerAsBytes
=>
529 write
!(f
, "a raw memory access tried to access part of a pointer value as raw \
531 ReadBytesAsPointer
=>
532 write
!(f
, "a memory access tried to interpret some bytes as a pointer"),
534 write
!(f
, "tried to read from foreign (extern) static"),
535 InvalidPointerMath
=>
536 write
!(f
, "attempted to do invalid arithmetic on pointers that would leak base \
537 addresses, e.g., comparing pointers into different allocations"),
539 write
!(f
, "tried to access a dead local variable"),
540 DerefFunctionPointer
=>
541 write
!(f
, "tried to dereference a function pointer"),
543 write
!(f
, "tried to treat a memory pointer as a function pointer"),
545 write
!(f
, "reached the maximum number of representable TLS keys"),
547 write
!(f
, "accessed an invalid (unallocated) TLS key"),
548 CalledClosureAsFunction
=>
549 write
!(f
, "tried to call a closure through a function pointer"),
550 VtableForArgumentlessMethod
=>
551 write
!(f
, "tried to call a vtable function without arguments"),
552 ModifiedConstantMemory
=>
553 write
!(f
, "tried to modify constant memory"),
555 write
!(f
, "tried to modify a static's initial value from another static's \
557 ReallocateNonBasePtr
=>
558 write
!(f
, "tried to reallocate with a pointer not to the beginning of an \
560 DeallocateNonBasePtr
=>
561 write
!(f
, "tried to deallocate with a pointer not to the beginning of an \
563 HeapAllocZeroBytes
=>
564 write
!(f
, "tried to re-, de- or allocate zero bytes on the heap"),
565 ReadFromReturnPointer
=>
566 write
!(f
, "tried to read from the return pointer"),
567 UnimplementedTraitSelection
=>
568 write
!(f
, "there were unresolved type arguments during trait selection"),
570 write
!(f
, "invalid boolean operation"),
571 UnterminatedCString(_
) =>
572 write
!(f
, "attempted to get length of a null-terminated string, but no null \
573 found before end of allocation"),
575 write
!(f
, "attempted to read undefined bytes"),
576 HeapAllocNonPowerOfTwoAlignment(_
) =>
577 write
!(f
, "tried to re-, de-, or allocate heap memory with alignment that is \
578 not a power of two"),
579 Unsupported(ref msg
) =>
580 write
!(f
, "{}", msg
),
581 ConstPropUnsupported(ref msg
) =>
582 write
!(f
, "Constant propagation encountered an unsupported situation: {}", msg
),
587 /// Error information for when the program exhausted the resources granted to it
588 /// by the interpreter.
589 pub enum ResourceExhaustionInfo
{
590 /// The stack grew too big.
591 StackFrameLimitReached
,
592 /// The program ran into an infinite loop.
596 impl fmt
::Debug
for ResourceExhaustionInfo
{
597 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
598 use ResourceExhaustionInfo
::*;
600 StackFrameLimitReached
=>
601 write
!(f
, "reached the configured maximum number of stack frames"),
603 write
!(f
, "duplicate interpreter state observed here, const evaluation will never \
609 pub enum InterpError
<'tcx
> {
610 /// The program panicked.
611 Panic(PanicInfo
<u64>),
612 /// The program caused undefined behavior.
613 UndefinedBehavior(UndefinedBehaviorInfo
),
614 /// The program did something the interpreter does not support (some of these *might* be UB
615 /// but the interpreter is not sure).
616 Unsupported(UnsupportedOpInfo
<'tcx
>),
617 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
618 InvalidProgram(InvalidProgramInfo
<'tcx
>),
619 /// The program exhausted the interpreter's resources (stack/heap too big,
620 /// execution takes too long, ...).
621 ResourceExhaustion(ResourceExhaustionInfo
),
622 /// Stop execution for a machine-controlled reason. This is never raised by
623 /// the core engine itself.
624 MachineStop(Box
<dyn Any
+ Send
>),
627 pub type InterpResult
<'tcx
, T
= ()> = Result
<T
, InterpErrorInfo
<'tcx
>>;
629 impl fmt
::Display
for InterpError
<'_
> {
630 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
631 // Forward `Display` to `Debug`.
632 write
!(f
, "{:?}", self)
636 impl fmt
::Debug
for InterpError
<'_
> {
637 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
640 Unsupported(ref msg
) =>
641 write
!(f
, "{:?}", msg
),
642 InvalidProgram(ref msg
) =>
643 write
!(f
, "{:?}", msg
),
644 UndefinedBehavior(ref msg
) =>
645 write
!(f
, "{:?}", msg
),
646 ResourceExhaustion(ref msg
) =>
647 write
!(f
, "{:?}", msg
),
649 write
!(f
, "{:?}", msg
),
651 write
!(f
, "machine caused execution to stop"),