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, InboundsCheck, 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
<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 pub call_site
: Span
, // this span is in the caller!
53 pub instance
: ty
::Instance
<'tcx
>,
54 pub lint_root
: Option
<hir
::HirId
>,
57 impl<'tcx
> fmt
::Display
for FrameInfo
<'tcx
> {
58 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
60 if tcx
.def_key(self.instance
.def_id()).disambiguated_data
.data
61 == DefPathData
::ClosureExpr
63 write
!(f
, "inside call to closure")?
;
65 write
!(f
, "inside call to `{}`", self.instance
)?
;
67 if !self.call_site
.is_dummy() {
68 let lo
= tcx
.sess
.source_map().lookup_char_pos_adj(self.call_site
.lo());
69 write
!(f
, " at {}:{}:{}", lo
.filename
, lo
.line
, lo
.col
.to_usize() + 1)?
;
76 impl<'a
, 'gcx
, 'tcx
> ConstEvalErr
<'tcx
> {
77 pub fn struct_error(&self,
78 tcx
: TyCtxtAt
<'a
, 'gcx
, 'tcx
>,
80 -> Result
<DiagnosticBuilder
<'tcx
>, ErrorHandled
>
82 self.struct_generic(tcx
, message
, None
)
85 pub fn report_as_error(&self,
86 tcx
: TyCtxtAt
<'a
, 'gcx
, 'tcx
>,
89 let err
= self.struct_error(tcx
, message
);
93 ErrorHandled
::Reported
99 pub fn report_as_lint(&self,
100 tcx
: TyCtxtAt
<'a
, 'gcx
, 'tcx
>,
102 lint_root
: hir
::HirId
,
105 let lint
= self.struct_generic(
112 if let Some(span
) = span
{
113 let primary_spans
= lint
.span
.primary_spans().to_vec();
114 // point at the actual error as the primary span
115 lint
.replace_span_with(span
);
116 // point to the `const` statement as a secondary span
117 // they don't have any label
118 for sp
in primary_spans
{
120 lint
.span_label(sp
, "");
125 ErrorHandled
::Reported
133 tcx
: TyCtxtAt
<'a
, 'gcx
, 'tcx
>,
135 lint_root
: Option
<hir
::HirId
>,
136 ) -> Result
<DiagnosticBuilder
<'tcx
>, ErrorHandled
> {
138 InterpError
::Layout(LayoutError
::Unknown(_
)) |
139 InterpError
::TooGeneric
=> return Err(ErrorHandled
::TooGeneric
),
140 InterpError
::Layout(LayoutError
::SizeOverflow(_
)) |
141 InterpError
::TypeckError
=> return Err(ErrorHandled
::Reported
),
144 trace
!("reporting const eval failure at {:?}", self.span
);
145 let mut err
= if let Some(lint_root
) = lint_root
{
146 let hir_id
= self.stacktrace
149 .filter_map(|frame
| frame
.lint_root
)
151 .unwrap_or(lint_root
);
152 tcx
.struct_span_lint_hir(
153 crate::rustc
::lint
::builtin
::CONST_ERR
,
159 struct_error(tcx
, message
)
161 err
.span_label(self.span
, self.error
.to_string());
162 // Skip the last, which is just the environment of the constant. The stacktrace
163 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
164 // on constant values.
165 if self.stacktrace
.len() > 0 {
166 for frame_info
in &self.stacktrace
[..self.stacktrace
.len()-1] {
167 err
.span_label(frame_info
.call_site
, frame_info
.to_string());
174 pub fn struct_error
<'a
, 'gcx
, 'tcx
>(
175 tcx
: TyCtxtAt
<'a
, 'gcx
, 'tcx
>,
177 ) -> DiagnosticBuilder
<'tcx
> {
178 struct_span_err
!(tcx
.sess
, tcx
.span
, E0080
, "{}", msg
)
181 #[derive(Debug, Clone)]
182 pub struct EvalError
<'tcx
> {
183 pub kind
: InterpError
<'tcx
, u64>,
184 pub backtrace
: Option
<Box
<Backtrace
>>,
187 impl<'tcx
> EvalError
<'tcx
> {
188 pub fn print_backtrace(&mut self) {
189 if let Some(ref mut backtrace
) = self.backtrace
{
190 print_backtrace(&mut *backtrace
);
195 fn print_backtrace(backtrace
: &mut Backtrace
) {
197 eprintln
!("\n\nAn error occurred in miri:\n{:?}", backtrace
);
200 impl<'tcx
> From
<InterpError
<'tcx
, u64>> for EvalError
<'tcx
> {
201 fn from(kind
: InterpError
<'tcx
, u64>) -> Self {
202 let backtrace
= match env
::var("RUST_CTFE_BACKTRACE") {
203 // matching RUST_BACKTRACE, we treat "0" the same as "not present".
204 Ok(ref val
) if val
!= "0" => {
205 let mut backtrace
= Backtrace
::new_unresolved();
207 if val
== "immediate" {
209 print_backtrace(&mut backtrace
);
212 Some(Box
::new(backtrace
))
224 pub type AssertMessage
<'tcx
> = InterpError
<'tcx
, mir
::Operand
<'tcx
>>;
226 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
227 pub enum InterpError
<'tcx
, O
> {
228 /// This variant is used by machines to signal their own errors that do not
229 /// match an existing variant.
230 MachineError(String
),
232 FunctionAbiMismatch(Abi
, Abi
),
233 FunctionArgMismatch(Ty
<'tcx
>, Ty
<'tcx
>),
234 FunctionRetMismatch(Ty
<'tcx
>, Ty
<'tcx
>),
235 FunctionArgCountMismatch
,
237 UnterminatedCString(Pointer
),
238 DanglingPointerDeref
,
241 InvalidFunctionPointer
,
243 InvalidDiscriminant(ScalarMaybeUndef
),
246 check
: InboundsCheck
,
247 allocation_size
: Size
,
249 InvalidNullPointerUsage
,
254 ReadUndefBytes(Size
),
256 InvalidBoolOp(mir
::BinOp
),
257 Unimplemented(String
),
258 DerefFunctionPointer
,
260 BoundsCheck { len: O, index: O }
,
261 Overflow(mir
::BinOp
),
267 StackFrameLimitReached
,
270 AbiViolation(String
),
271 AlignmentCheckFailed
{
275 ValidationFailure(String
),
276 CalledClosureAsFunction
,
277 VtableForArgumentlessMethod
,
278 ModifiedConstantMemory
,
282 TypeNotPrimitive(Ty
<'tcx
>),
283 ReallocatedWrongMemoryKind(String
, String
),
284 DeallocatedWrongMemoryKind(String
, String
),
285 ReallocateNonBasePtr
,
286 DeallocateNonBasePtr
,
287 IncorrectAllocationInformation(Size
, Size
, Align
, Align
),
288 Layout(layout
::LayoutError
<'tcx
>),
290 HeapAllocNonPowerOfTwoAlignment(u64),
298 ReadFromReturnPointer
,
299 PathNotFound(Vec
<String
>),
300 UnimplementedTraitSelection
,
301 /// Abort in case type errors are reached
303 /// Resolution can fail if we are in a too generic context
305 /// Cannot compute this constant because it depends on another one
306 /// which already produced an error
308 GeneratorResumedAfterReturn
,
309 GeneratorResumedAfterPanic
,
313 pub type EvalResult
<'tcx
, T
= ()> = Result
<T
, EvalError
<'tcx
>>;
315 impl<'tcx
, O
> InterpError
<'tcx
, O
> {
316 pub fn description(&self) -> &str {
317 use self::InterpError
::*;
319 MachineError(ref inner
) => inner
,
320 FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
321 | FunctionArgCountMismatch
=>
322 "tried to call a function through a function pointer of incompatible type",
323 InvalidMemoryAccess
=>
324 "tried to access memory through an invalid pointer",
325 DanglingPointerDeref
=>
326 "dangling pointer was dereferenced",
328 "tried to deallocate dangling pointer",
329 InvalidFunctionPointer
=>
330 "tried to use a function pointer after offsetting it",
332 "invalid boolean value read",
333 InvalidDiscriminant(..) =>
334 "invalid enum discriminant value read",
335 PointerOutOfBounds { .. }
=>
336 "pointer offset outside bounds of allocation",
337 InvalidNullPointerUsage
=>
338 "invalid use of NULL pointer",
339 ValidationFailure(..) =>
340 "type validation failed",
341 ReadPointerAsBytes
=>
342 "a raw memory access tried to access part of a pointer value as raw bytes",
343 ReadBytesAsPointer
=>
344 "a memory access tried to interpret some bytes as a pointer",
346 "tried to read from foreign (extern) static",
347 InvalidPointerMath
=>
348 "attempted to do invalid arithmetic on pointers that would leak base addresses, \
349 e.g., comparing pointers into different allocations",
351 "attempted to read undefined bytes",
353 "tried to access a dead local variable",
355 "invalid boolean operation",
356 Unimplemented(ref msg
) => msg
,
357 DerefFunctionPointer
=>
358 "tried to dereference a function pointer",
360 "tried to treat a memory pointer as a function pointer",
362 "array index out of bounds",
368 "tried to interpret an invalid 32-bit value as a char",
369 StackFrameLimitReached
=>
370 "reached the configured maximum number of stack frames",
372 "reached the maximum number of representable TLS keys",
374 "accessed an invalid (unallocated) TLS key",
375 AbiViolation(ref msg
) => msg
,
376 AlignmentCheckFailed{..}
=>
377 "tried to execute a misaligned read or write",
378 CalledClosureAsFunction
=>
379 "tried to call a closure through a function pointer",
380 VtableForArgumentlessMethod
=>
381 "tried to call a vtable function without arguments",
382 ModifiedConstantMemory
=>
383 "tried to modify constant memory",
385 "tried to modify a static's initial value from another static's initializer",
387 "`assume` argument was false",
389 "miri does not support inline assembly",
390 TypeNotPrimitive(_
) =>
391 "expected primitive type, got nonprimitive",
392 ReallocatedWrongMemoryKind(_
, _
) =>
393 "tried to reallocate memory from one kind to another",
394 DeallocatedWrongMemoryKind(_
, _
) =>
395 "tried to deallocate memory of the wrong kind",
396 ReallocateNonBasePtr
=>
397 "tried to reallocate with a pointer not to the beginning of an existing object",
398 DeallocateNonBasePtr
=>
399 "tried to deallocate with a pointer not to the beginning of an existing object",
400 IncorrectAllocationInformation(..) =>
401 "tried to deallocate or reallocate using incorrect alignment or size",
403 "rustc layout computation failed",
404 UnterminatedCString(_
) =>
405 "attempted to get length of a null terminated string, but no null found before end \
407 HeapAllocZeroBytes
=>
408 "tried to re-, de- or allocate zero bytes on the heap",
409 HeapAllocNonPowerOfTwoAlignment(_
) =>
410 "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
413 "entered unreachable code",
415 "the evaluated program panicked",
416 ReadFromReturnPointer
=>
417 "tried to read from the return pointer",
419 "a path could not be resolved, maybe the crate is not loaded",
420 UnimplementedTraitSelection
=>
421 "there were unresolved type arguments during trait selection",
423 "encountered constants with type errors, stopping evaluation",
425 "encountered overly generic constant",
426 ReferencedConstant
=>
427 "referenced constant has errors",
428 Overflow(mir
::BinOp
::Add
) => "attempt to add with overflow",
429 Overflow(mir
::BinOp
::Sub
) => "attempt to subtract with overflow",
430 Overflow(mir
::BinOp
::Mul
) => "attempt to multiply with overflow",
431 Overflow(mir
::BinOp
::Div
) => "attempt to divide with overflow",
432 Overflow(mir
::BinOp
::Rem
) => "attempt to calculate the remainder with overflow",
433 OverflowNeg
=> "attempt to negate with overflow",
434 Overflow(mir
::BinOp
::Shr
) => "attempt to shift right with overflow",
435 Overflow(mir
::BinOp
::Shl
) => "attempt to shift left with overflow",
436 Overflow(op
) => bug
!("{:?} cannot overflow", op
),
437 DivisionByZero
=> "attempt to divide by zero",
438 RemainderByZero
=> "attempt to calculate the remainder with a divisor of zero",
439 GeneratorResumedAfterReturn
=> "generator resumed after completion",
440 GeneratorResumedAfterPanic
=> "generator resumed after panicking",
442 "duplicate interpreter state observed here, const evaluation will never terminate",
447 impl<'tcx
> fmt
::Display
for EvalError
<'tcx
> {
448 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
449 write
!(f
, "{}", self.kind
)
453 impl<'tcx
> fmt
::Display
for InterpError
<'tcx
, u64> {
454 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
455 write
!(f
, "{:?}", self)
459 impl<'tcx
, O
: fmt
::Debug
> fmt
::Debug
for InterpError
<'tcx
, O
> {
460 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
461 use self::InterpError
::*;
463 PointerOutOfBounds { ptr, check, allocation_size }
=> {
464 write
!(f
, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
465 allocation {} which has size {}",
467 InboundsCheck
::Live
=> " and live",
468 InboundsCheck
::MaybeDead
=> "",
470 ptr
.offset
.bytes(), ptr
.alloc_id
, allocation_size
.bytes())
472 ValidationFailure(ref err
) => {
473 write
!(f
, "type validation failed: {}", err
)
475 NoMirFor(ref func
) => write
!(f
, "no mir for `{}`", func
),
476 FunctionAbiMismatch(caller_abi
, callee_abi
) =>
477 write
!(f
, "tried to call a function with ABI {:?} using caller ABI {:?}",
478 callee_abi
, caller_abi
),
479 FunctionArgMismatch(caller_ty
, callee_ty
) =>
480 write
!(f
, "tried to call a function with argument of type {:?} \
481 passing data of type {:?}",
482 callee_ty
, caller_ty
),
483 FunctionRetMismatch(caller_ty
, callee_ty
) =>
484 write
!(f
, "tried to call a function with return type {:?} \
485 passing return place of type {:?}",
486 callee_ty
, caller_ty
),
487 FunctionArgCountMismatch
=>
488 write
!(f
, "tried to call a function with incorrect number of arguments"),
489 BoundsCheck { ref len, ref index }
=>
490 write
!(f
, "index out of bounds: the len is {:?} but the index is {:?}", len
, index
),
491 ReallocatedWrongMemoryKind(ref old
, ref new
) =>
492 write
!(f
, "tried to reallocate memory from {} to {}", old
, new
),
493 DeallocatedWrongMemoryKind(ref old
, ref new
) =>
494 write
!(f
, "tried to deallocate {} memory but gave {} as the kind", old
, new
),
495 Intrinsic(ref err
) =>
496 write
!(f
, "{}", err
),
498 write
!(f
, "tried to interpret an invalid 32-bit value as a char: {}", c
),
499 AlignmentCheckFailed { required, has }
=>
500 write
!(f
, "tried to access memory with alignment {}, but alignment {} is required",
501 has
.bytes(), required
.bytes()),
502 TypeNotPrimitive(ty
) =>
503 write
!(f
, "expected primitive type, got {}", ty
),
505 write
!(f
, "rustc layout computation failed: {:?}", err
),
506 PathNotFound(ref path
) =>
507 write
!(f
, "Cannot find path {:?}", path
),
508 MachineError(ref inner
) =>
509 write
!(f
, "{}", inner
),
510 IncorrectAllocationInformation(size
, size2
, align
, align2
) =>
511 write
!(f
, "incorrect alloc info: expected size {} and align {}, \
512 got size {} and align {}",
513 size
.bytes(), align
.bytes(), size2
.bytes(), align2
.bytes()),
514 Panic { ref msg, line, col, ref file }
=>
515 write
!(f
, "the evaluated program panicked at '{}', {}:{}:{}", msg
, file
, line
, col
),
516 InvalidDiscriminant(val
) =>
517 write
!(f
, "encountered invalid enum discriminant {}", val
),
518 _
=> write
!(f
, "{}", self.description()),