1use std::any::Any;
2use std::backtrace::Backtrace;
3use std::borrow::Cow;
4use std::{convert, fmt, mem, ops};
56use either::Either;
7use rustc_abi::{Align, Size, VariantIdx};
8use rustc_data_structures::sync::Lock;
9use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg};
10use rustc_macros::{StableHash, TyDecodable, TyEncodable};
11use rustc_session::CtfeBacktrace;
12use rustc_span::def_id::DefId;
13use rustc_span::{DUMMY_SP, Span, Symbol};
1415use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar};
16use crate::diagnostics;
17use crate::mir::interpret::CtfeProvenance;
18use crate::mir::{ConstAlloc, ConstValue};
19use crate::ty::{self, Ty, TyCtxt, ValTree, layout, tls};
2021#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ErrorHandled {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ErrorHandled::Reported(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"Reported", __self_0, &__self_1),
ErrorHandled::TooGeneric(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"TooGeneric", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for ErrorHandled { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ErrorHandled { }
#[automatically_derived]
impl ::core::clone::Clone for ErrorHandled {
#[inline]
fn clone(&self) -> ErrorHandled {
let _: ::core::clone::AssertParamIsClone<ReportedErrorInfo>;
let _: ::core::clone::AssertParamIsClone<Span>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ErrorHandled { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ErrorHandled {
#[inline]
fn eq(&self, other: &ErrorHandled) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(ErrorHandled::Reported(__self_0, __self_1),
ErrorHandled::Reported(__arg1_0, __arg1_1)) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
(ErrorHandled::TooGeneric(__self_0),
ErrorHandled::TooGeneric(__arg1_0)) => __self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ErrorHandled {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<ReportedErrorInfo>;
let _: ::core::cmp::AssertParamIsEq<Span>;
}
}Eq, const _: () =
{
impl ::rustc_data_structures::stable_hash::StableHash for ErrorHandled
{
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
match *self {
ErrorHandled::Reported(ref __binding_0, ref __binding_1) =>
{
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
ErrorHandled::TooGeneric(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, const _: () =
{
impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for ErrorHandled {
fn encode(&self, __encoder: &mut __E) {
let disc =
match *self {
ErrorHandled::Reported(ref __binding_0, ref __binding_1) =>
{
0usize
}
ErrorHandled::TooGeneric(ref __binding_0) => { 1usize }
};
::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
match *self {
ErrorHandled::Reported(ref __binding_0, ref __binding_1) =>
{
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
}
ErrorHandled::TooGeneric(ref __binding_0) => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
}
}
}
}
};TyEncodable, const _: () =
{
impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for ErrorHandled {
fn decode(__decoder: &mut __D) -> Self {
match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
{
0usize => {
ErrorHandled::Reported(::rustc_serialize::Decodable::decode(__decoder),
::rustc_serialize::Decodable::decode(__decoder))
}
1usize => {
ErrorHandled::TooGeneric(::rustc_serialize::Decodable::decode(__decoder))
}
n => {
::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `ErrorHandled`, expected 0..2, actual {0}",
n));
}
}
}
}
};TyDecodable)]
22pub enum ErrorHandled {
23/// Already reported an error for this evaluation, and the compilation is
24 /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
25Reported(ReportedErrorInfo, Span),
26/// Don't emit an error, the evaluation failed because the MIR was generic
27 /// and the args didn't fully monomorphize it.
28TooGeneric(Span),
29}
3031impl From<ReportedErrorInfo> for ErrorHandled {
32#[inline]
33fn from(error: ReportedErrorInfo) -> ErrorHandled {
34 ErrorHandled::Reported(error, DUMMY_SP)
35 }
36}
3738impl ErrorHandled {
39pub(crate) fn with_span(self, span: Span) -> Self {
40match self {
41 ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
42 ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
43 }
44 }
4546pub fn emit_note(&self, tcx: TyCtxt<'_>) {
47match self {
48&ErrorHandled::Reported(err, span) => {
49if !err.allowed_in_infallible && !span.is_dummy() {
50tcx.dcx().emit_note(diagnostics::ErroneousConstant { span });
51 }
52 }
53&ErrorHandled::TooGeneric(_) => {}
54 }
55 }
56}
5758#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ReportedErrorInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"ReportedErrorInfo", "error", &self.error,
"allowed_in_infallible", &&self.allowed_in_infallible)
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for ReportedErrorInfo { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ReportedErrorInfo { }
#[automatically_derived]
impl ::core::clone::Clone for ReportedErrorInfo {
#[inline]
fn clone(&self) -> ReportedErrorInfo {
let _: ::core::clone::AssertParamIsClone<ErrorGuaranteed>;
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ReportedErrorInfo { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ReportedErrorInfo {
#[inline]
fn eq(&self, other: &ReportedErrorInfo) -> bool {
self.allowed_in_infallible == other.allowed_in_infallible &&
self.error == other.error
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ReportedErrorInfo {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<ErrorGuaranteed>;
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq, const _: () =
{
impl ::rustc_data_structures::stable_hash::StableHash for
ReportedErrorInfo {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
ReportedErrorInfo {
error: ref __binding_0,
allowed_in_infallible: ref __binding_1 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, const _: () =
{
impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for ReportedErrorInfo {
fn encode(&self, __encoder: &mut __E) {
let ReportedErrorInfo {
error: ref __binding_0,
allowed_in_infallible: ref __binding_1 } = *self;
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
}
}
};TyEncodable, const _: () =
{
impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for ReportedErrorInfo {
fn decode(__decoder: &mut __D) -> Self {
ReportedErrorInfo {
error: ::rustc_serialize::Decodable::decode(__decoder),
allowed_in_infallible: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};TyDecodable)]
59pub struct ReportedErrorInfo {
60 error: ErrorGuaranteed,
61/// Whether this error is allowed to show up even in otherwise "infallible" promoteds.
62 /// This is for things like overflows during size computation or resource exhaustion.
63allowed_in_infallible: bool,
64}
6566impl ReportedErrorInfo {
67#[inline]
68pub fn const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
69ReportedErrorInfo { allowed_in_infallible: false, error }
70 }
7172/// Use this when the error that led to this is *not* a const-eval error
73 /// (e.g., a layout or type checking error).
74#[inline]
75pub fn non_const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
76ReportedErrorInfo { allowed_in_infallible: true, error }
77 }
7879/// Use this when the error that led to this *is* a const-eval error, but
80 /// we do allow it to occur in infallible constants (e.g., resource exhaustion).
81#[inline]
82pub fn allowed_in_infallible(error: ErrorGuaranteed) -> ReportedErrorInfo {
83ReportedErrorInfo { allowed_in_infallible: true, error }
84 }
8586pub fn is_allowed_in_infallible(&self) -> bool {
87self.allowed_in_infallible
88 }
89}
9091impl From<ReportedErrorInfo> for ErrorGuaranteed {
92#[inline]
93fn from(val: ReportedErrorInfo) -> Self {
94val.error
95 }
96}
9798/// An error type for the `const_to_valtree` query. Some error should be reported with a "use-site span",
99/// which means the query cannot emit the error, so those errors are represented as dedicated variants here.
100#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ValTreeCreationError<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ValTreeCreationError::NodesOverflow =>
::core::fmt::Formatter::write_str(f, "NodesOverflow"),
ValTreeCreationError::InvalidConst =>
::core::fmt::Formatter::write_str(f, "InvalidConst"),
ValTreeCreationError::NonSupportedType(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"NonSupportedType", &__self_0),
ValTreeCreationError::CyclicConst =>
::core::fmt::Formatter::write_str(f, "CyclicConst"),
ValTreeCreationError::ErrorHandled(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ErrorHandled", &__self_0),
}
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for ValTreeCreationError<'tcx> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for ValTreeCreationError<'tcx> {
}
#[automatically_derived]
impl<'tcx> ::core::clone::Clone for ValTreeCreationError<'tcx> {
#[inline]
fn clone(&self) -> ValTreeCreationError<'tcx> {
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
let _: ::core::clone::AssertParamIsClone<ErrorHandled>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for ValTreeCreationError<'tcx>
{
}
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for ValTreeCreationError<'tcx> {
#[inline]
fn eq(&self, other: &ValTreeCreationError<'tcx>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(ValTreeCreationError::NonSupportedType(__self_0),
ValTreeCreationError::NonSupportedType(__arg1_0)) =>
__self_0 == __arg1_0,
(ValTreeCreationError::ErrorHandled(__self_0),
ValTreeCreationError::ErrorHandled(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for ValTreeCreationError<'tcx> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
let _: ::core::cmp::AssertParamIsEq<ErrorHandled>;
}
}Eq, const _: () =
{
impl<'tcx> ::rustc_data_structures::stable_hash::StableHash for
ValTreeCreationError<'tcx> {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
match *self {
ValTreeCreationError::NodesOverflow => {}
ValTreeCreationError::InvalidConst => {}
ValTreeCreationError::NonSupportedType(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
ValTreeCreationError::CyclicConst => {}
ValTreeCreationError::ErrorHandled(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, const _: () =
{
impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for ValTreeCreationError<'tcx> {
fn encode(&self, __encoder: &mut __E) {
let disc =
match *self {
ValTreeCreationError::NodesOverflow => { 0usize }
ValTreeCreationError::InvalidConst => { 1usize }
ValTreeCreationError::NonSupportedType(ref __binding_0) => {
2usize
}
ValTreeCreationError::CyclicConst => { 3usize }
ValTreeCreationError::ErrorHandled(ref __binding_0) => {
4usize
}
};
::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
match *self {
ValTreeCreationError::NodesOverflow => {}
ValTreeCreationError::InvalidConst => {}
ValTreeCreationError::NonSupportedType(ref __binding_0) => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
}
ValTreeCreationError::CyclicConst => {}
ValTreeCreationError::ErrorHandled(ref __binding_0) => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
}
}
}
}
};TyEncodable, const _: () =
{
impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for ValTreeCreationError<'tcx> {
fn decode(__decoder: &mut __D) -> Self {
match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
{
0usize => { ValTreeCreationError::NodesOverflow }
1usize => { ValTreeCreationError::InvalidConst }
2usize => {
ValTreeCreationError::NonSupportedType(::rustc_serialize::Decodable::decode(__decoder))
}
3usize => { ValTreeCreationError::CyclicConst }
4usize => {
ValTreeCreationError::ErrorHandled(::rustc_serialize::Decodable::decode(__decoder))
}
n => {
::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `ValTreeCreationError`, expected 0..5, actual {0}",
n));
}
}
}
}
};TyDecodable)]
101pub enum ValTreeCreationError<'tcx> {
102/// The constant is too big to be valtree'd.
103NodesOverflow,
104/// The constant references mutable or external memory, so it cannot be valtree'd.
105InvalidConst,
106/// Values of this type, or this particular value, are not supported as valtrees.
107NonSupportedType(Ty<'tcx>),
108/// Trying to valtree this constant would cause the valtree to have cycles.
109CyclicConst,
110/// The error has already been handled by const evaluation.
111ErrorHandled(ErrorHandled),
112}
113114impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> {
115fn from(err: ErrorHandled) -> Self {
116 ValTreeCreationError::ErrorHandled(err)
117 }
118}
119120impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
121fn from(err: InterpErrorInfo<'tcx>) -> Self {
122// An error occurred outside the const-eval query, as part of constructing the valtree. We
123 // don't currently preserve the details of this error, since `InterpErrorInfo` cannot be put
124 // into a query result and it can only be access of some mutable or external memory.
125let (_kind, backtrace) = err.into_parts();
126backtrace.print_backtrace();
127 ValTreeCreationError::InvalidConst128 }
129}
130131impl<'tcx> ValTreeCreationError<'tcx> {
132pub(crate) fn with_span(self, span: Span) -> Self {
133use ValTreeCreationError::*;
134match self {
135ErrorHandled(handled) => ErrorHandled(handled.with_span(span)),
136 other => other,
137 }
138 }
139}
140141pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
142pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
143pub type EvalToConstValueResult<'tcx> = Result<ConstValue, ErrorHandled>;
144pub type EvalToValTreeResult<'tcx> = Result<ValTree<'tcx>, ValTreeCreationError<'tcx>>;
145146#[cfg(target_pointer_width = "64")]
147const _: [(); 8] = [(); ::std::mem::size_of::<InterpErrorInfo<'_>>()];rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);
148149/// Packages the kind of error we got from the const code interpreter
150/// up with a Rust-level backtrace of where the error occurred.
151/// These should always be constructed by calling `.into()` on
152/// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
153/// macros for this.
154///
155/// Interpreter errors must *not* be silently discarded (that will lead to a panic). Instead,
156/// explicitly call `discard_err` if this is really the right thing to do. Note that if
157/// this happens during const-eval or in Miri, it could lead to a UB error being lost!
158#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InterpErrorInfo<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InterpErrorInfo", &&self.0)
}
}Debug)]
159pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
160161#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InterpErrorInfoInner<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"InterpErrorInfoInner", "kind", &self.kind, "backtrace",
&&self.backtrace)
}
}Debug)]
162struct InterpErrorInfoInner<'tcx> {
163 kind: InterpErrorKind<'tcx>,
164 backtrace: InterpErrorBacktrace,
165}
166167#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InterpErrorBacktrace {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"InterpErrorBacktrace", "backtrace", &&self.backtrace)
}
}Debug)]
168pub struct InterpErrorBacktrace {
169 backtrace: Option<Box<Backtrace>>,
170}
171172impl InterpErrorBacktrace {
173pub fn new() -> InterpErrorBacktrace {
174let capture_backtrace = tls::with_opt(|tcx| {
175if let Some(tcx) = tcx {
176*Lock::borrow(&tcx.sess.ctfe_backtrace)
177 } else {
178 CtfeBacktrace::Disabled179 }
180 });
181182let backtrace = match capture_backtrace {
183 CtfeBacktrace::Disabled => None,
184 CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
185 CtfeBacktrace::Immediate => {
186// Print it now.
187let backtrace = Backtrace::force_capture();
188print_backtrace(&backtrace);
189None190 }
191 };
192193InterpErrorBacktrace { backtrace }
194 }
195196pub fn print_backtrace(&self) {
197if let Some(backtrace) = self.backtrace.as_ref() {
198print_backtrace(backtrace);
199 }
200 }
201}
202203impl<'tcx> InterpErrorInfo<'tcx> {
204pub fn into_parts(self) -> (InterpErrorKind<'tcx>, InterpErrorBacktrace) {
205let InterpErrorInfo(InterpErrorInfoInner { kind, backtrace }) = self;
206 (kind, backtrace)
207 }
208209pub fn into_kind(self) -> InterpErrorKind<'tcx> {
210self.0.kind
211 }
212213pub fn from_parts(kind: InterpErrorKind<'tcx>, backtrace: InterpErrorBacktrace) -> Self {
214Self(Box::new(InterpErrorInfoInner { kind, backtrace }))
215 }
216217#[inline]
218pub fn kind(&self) -> &InterpErrorKind<'tcx> {
219&self.0.kind
220 }
221222/// Turn the given error into a human-readable string. Expects the string to be printed, so if
223 /// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that
224 /// triggered the error.
225 ///
226 /// This is NOT the preferred way to render an error; use `report` from `const_eval` instead.
227 /// However, this is useful when error messages appear in ICEs.
228pub fn to_string(&self) -> String {
229self.0.backtrace.print_backtrace();
230self.0.kind.to_string()
231 }
232}
233234fn print_backtrace(backtrace: &Backtrace) {
235{
::std::io::_eprint(format_args!("\n\nAn error occurred in the MIR interpreter:\n{0}\n",
backtrace));
};eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}");
236}
237238impl From<ErrorHandled> for InterpErrorInfo<'_> {
239fn from(err: ErrorHandled) -> Self {
240 InterpErrorKind::InvalidProgram(match err {
241 ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
242 ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
243 })
244 .into()
245 }
246}
247248impl<'tcx> From<InterpErrorKind<'tcx>> for InterpErrorInfo<'tcx> {
249fn from(kind: InterpErrorKind<'tcx>) -> Self {
250InterpErrorInfo(Box::new(InterpErrorInfoInner {
251kind,
252 backtrace: InterpErrorBacktrace::new(),
253 }))
254 }
255}
256257/// Details of why a pointer had to be in-bounds.
258#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CheckInAllocMsg {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
CheckInAllocMsg::MemoryAccess =>
::core::fmt::Formatter::write_str(f, "MemoryAccess"),
CheckInAllocMsg::InboundsPointerArithmetic =>
::core::fmt::Formatter::write_str(f,
"InboundsPointerArithmetic"),
CheckInAllocMsg::Dereferenceable(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Dereferenceable", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for CheckInAllocMsg { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CheckInAllocMsg { }
#[automatically_derived]
impl ::core::clone::Clone for CheckInAllocMsg {
#[inline]
fn clone(&self) -> CheckInAllocMsg {
let _: ::core::clone::AssertParamIsClone<&'static str>;
*self
}
}Clone)]
259pub enum CheckInAllocMsg {
260/// We are accessing memory.
261MemoryAccess,
262/// We are doing pointer arithmetic.
263InboundsPointerArithmetic,
264/// None of the above -- generic/unspecific inbounds test.
265 /// The string is the subject of the test, e.g. "pointer".
266Dereferenceable(&'static str),
267}
268269impl fmt::Displayfor CheckInAllocMsg {
270fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271use CheckInAllocMsg::*;
272match self {
273MemoryAccess => f.write_fmt(format_args!("memory access failed"))write!(f, "memory access failed"),
274InboundsPointerArithmetic => f.write_fmt(format_args!("in-bounds pointer arithmetic failed"))write!(f, "in-bounds pointer arithmetic failed"),
275Dereferenceable(what) => f.write_fmt(format_args!("{0} not dereferenceable", what))write!(f, "{what} not dereferenceable"),
276 }
277 }
278}
279280/// Details of which pointer is not aligned.
281#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CheckAlignMsg {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
CheckAlignMsg::AccessedPtr => "AccessedPtr",
CheckAlignMsg::BasedOn => "BasedOn",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for CheckAlignMsg { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CheckAlignMsg { }
#[automatically_derived]
impl ::core::clone::Clone for CheckAlignMsg {
#[inline]
fn clone(&self) -> CheckAlignMsg { *self }
}Clone)]
282pub enum CheckAlignMsg {
283/// The accessed pointer did not have proper alignment.
284AccessedPtr,
285/// The access occurred with a place that was based on a misaligned pointer.
286BasedOn,
287}
288289#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InvalidMetaKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
InvalidMetaKind::SliceTooBig => "SliceTooBig",
InvalidMetaKind::TooBig => "TooBig",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for InvalidMetaKind { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InvalidMetaKind { }
#[automatically_derived]
impl ::core::clone::Clone for InvalidMetaKind {
#[inline]
fn clone(&self) -> InvalidMetaKind { *self }
}Clone)]
290pub enum InvalidMetaKind {
291/// Size of a `[T]` is too big
292SliceTooBig,
293/// Size of a DST is too big
294TooBig,
295}
296297impl IntoDiagArgfor InvalidMetaKind {
298fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
299 DiagArgValue::Str(Cow::Borrowed(match self {
300 InvalidMetaKind::SliceTooBig => "slice_too_big",
301 InvalidMetaKind::TooBig => "too_big",
302 }))
303 }
304}
305306/// Details of an access to uninitialized bytes / bad pointer bytes where it is not allowed.
307#[derive(#[automatically_derived]
impl ::core::fmt::Debug for BadBytesAccess {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"BadBytesAccess", "access", &self.access, "bad", &&self.bad)
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for BadBytesAccess { }
#[automatically_derived]
impl ::core::clone::Clone for BadBytesAccess {
#[inline]
fn clone(&self) -> BadBytesAccess {
let _: ::core::clone::AssertParamIsClone<AllocRange>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for BadBytesAccess { }Copy)]
308pub struct BadBytesAccess {
309/// Range of the original memory access.
310pub access: AllocRange,
311/// Range of the bad memory that was encountered. (Might not be maximal.)
312pub bad: AllocRange,
313}
314315/// Information about a misaligned pointer.
316#[derive(#[automatically_derived]
impl ::core::marker::Copy for Misalignment { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Misalignment { }
#[automatically_derived]
impl ::core::clone::Clone for Misalignment {
#[inline]
fn clone(&self) -> Misalignment {
let _: ::core::clone::AssertParamIsClone<Align>;
*self
}
}Clone, #[automatically_derived]
impl ::core::hash::Hash for Misalignment {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.has, state);
::core::hash::Hash::hash(&self.required, state)
}
}Hash, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Misalignment { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Misalignment {
#[inline]
fn eq(&self, other: &Misalignment) -> bool {
self.has == other.has && self.required == other.required
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Misalignment {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Align>;
}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for Misalignment {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Misalignment",
"has", &self.has, "required", &&self.required)
}
}Debug)]
317pub struct Misalignment {
318pub has: Align,
319pub required: Align,
320}
321322/// Error information for when the program caused Undefined Behavior.
323#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for UndefinedBehaviorInfo<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
UndefinedBehaviorInfo::Ub(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ub",
&__self_0),
UndefinedBehaviorInfo::ValidationError {
orig_ty: __self_0,
path: __self_1,
msg: __self_2,
ptr_bytes_warning: __self_3 } =>
::core::fmt::Formatter::debug_struct_field4_finish(f,
"ValidationError", "orig_ty", __self_0, "path", __self_1,
"msg", __self_2, "ptr_bytes_warning", &__self_3),
UndefinedBehaviorInfo::Unreachable =>
::core::fmt::Formatter::write_str(f, "Unreachable"),
UndefinedBehaviorInfo::BoundsCheckFailed {
len: __self_0, index: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"BoundsCheckFailed", "len", __self_0, "index", &__self_1),
UndefinedBehaviorInfo::DivisionByZero =>
::core::fmt::Formatter::write_str(f, "DivisionByZero"),
UndefinedBehaviorInfo::RemainderByZero =>
::core::fmt::Formatter::write_str(f, "RemainderByZero"),
UndefinedBehaviorInfo::DivisionOverflow =>
::core::fmt::Formatter::write_str(f, "DivisionOverflow"),
UndefinedBehaviorInfo::RemainderOverflow =>
::core::fmt::Formatter::write_str(f, "RemainderOverflow"),
UndefinedBehaviorInfo::PointerArithOverflow =>
::core::fmt::Formatter::write_str(f, "PointerArithOverflow"),
UndefinedBehaviorInfo::ArithOverflow { intrinsic: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"ArithOverflow", "intrinsic", &__self_0),
UndefinedBehaviorInfo::ShiftOverflow {
intrinsic: __self_0, shift_amount: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"ShiftOverflow", "intrinsic", __self_0, "shift_amount",
&__self_1),
UndefinedBehaviorInfo::InvalidMeta(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidMeta", &__self_0),
UndefinedBehaviorInfo::UnterminatedCString(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"UnterminatedCString", &__self_0),
UndefinedBehaviorInfo::PointerUseAfterFree(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"PointerUseAfterFree", __self_0, &__self_1),
UndefinedBehaviorInfo::PointerOutOfBounds {
alloc_id: __self_0,
alloc_size: __self_1,
ptr_offset: __self_2,
inbounds_size: __self_3,
msg: __self_4 } =>
::core::fmt::Formatter::debug_struct_field5_finish(f,
"PointerOutOfBounds", "alloc_id", __self_0, "alloc_size",
__self_1, "ptr_offset", __self_2, "inbounds_size", __self_3,
"msg", &__self_4),
UndefinedBehaviorInfo::DanglingIntPointer {
addr: __self_0, inbounds_size: __self_1, msg: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"DanglingIntPointer", "addr", __self_0, "inbounds_size",
__self_1, "msg", &__self_2),
UndefinedBehaviorInfo::AlignmentCheckFailed(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"AlignmentCheckFailed", __self_0, &__self_1),
UndefinedBehaviorInfo::WriteToReadOnly(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"WriteToReadOnly", &__self_0),
UndefinedBehaviorInfo::DerefFunctionPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"DerefFunctionPointer", &__self_0),
UndefinedBehaviorInfo::DerefVTablePointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"DerefVTablePointer", &__self_0),
UndefinedBehaviorInfo::DerefVaListPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"DerefVaListPointer", &__self_0),
UndefinedBehaviorInfo::DerefTypeIdPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"DerefTypeIdPointer", &__self_0),
UndefinedBehaviorInfo::InvalidBool(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidBool", &__self_0),
UndefinedBehaviorInfo::InvalidChar(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidChar", &__self_0),
UndefinedBehaviorInfo::InvalidTag(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidTag", &__self_0),
UndefinedBehaviorInfo::InvalidFunctionPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidFunctionPointer", &__self_0),
UndefinedBehaviorInfo::InvalidVaListPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidVaListPointer", &__self_0),
UndefinedBehaviorInfo::InvalidVTablePointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidVTablePointer", &__self_0),
UndefinedBehaviorInfo::InvalidVTableTrait {
vtable_dyn_type: __self_0, expected_dyn_type: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"InvalidVTableTrait", "vtable_dyn_type", __self_0,
"expected_dyn_type", &__self_1),
UndefinedBehaviorInfo::InvalidStr(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidStr", &__self_0),
UndefinedBehaviorInfo::InvalidUninitBytes(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidUninitBytes", &__self_0),
UndefinedBehaviorInfo::DeadLocal =>
::core::fmt::Formatter::write_str(f, "DeadLocal"),
UndefinedBehaviorInfo::UninhabitedEnumVariantWritten(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"UninhabitedEnumVariantWritten", &__self_0),
UndefinedBehaviorInfo::UninhabitedEnumVariantRead(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"UninhabitedEnumVariantRead", &__self_0),
UndefinedBehaviorInfo::InvalidNichedEnumVariantWritten {
enum_ty: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"InvalidNichedEnumVariantWritten", "enum_ty", &__self_0),
UndefinedBehaviorInfo::AbiMismatchArgument {
arg_idx: __self_0, caller_ty: __self_1, callee_ty: __self_2 }
=>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"AbiMismatchArgument", "arg_idx", __self_0, "caller_ty",
__self_1, "callee_ty", &__self_2),
UndefinedBehaviorInfo::AbiMismatchReturn {
caller_ty: __self_0, callee_ty: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"AbiMismatchReturn", "caller_ty", __self_0, "callee_ty",
&__self_1),
UndefinedBehaviorInfo::VaArgOutOfBounds =>
::core::fmt::Formatter::write_str(f, "VaArgOutOfBounds"),
UndefinedBehaviorInfo::CVariadicMismatch {
caller_is_c_variadic: __self_0, callee_is_c_variadic: __self_1
} =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"CVariadicMismatch", "caller_is_c_variadic", __self_0,
"callee_is_c_variadic", &__self_1),
UndefinedBehaviorInfo::CVariadicFixedCountMismatch {
caller: __self_0, callee: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"CVariadicFixedCountMismatch", "caller", __self_0, "callee",
&__self_1),
}
}
}Debug)]
324pub enum UndefinedBehaviorInfo<'tcx> {
325/// Free-form case. Only for errors that are never caught! Used by miri
326Ub(String),
327/// Validation error.
328ValidationError {
329 orig_ty: Ty<'tcx>,
330 path: Option<String>,
331 msg: String,
332 ptr_bytes_warning: bool,
333 },
334335/// Unreachable code was executed.
336Unreachable,
337/// A slice/array index projection went out-of-bounds.
338BoundsCheckFailed { len: u64, index: u64 },
339/// Something was divided by 0 (x / 0).
340DivisionByZero,
341/// Something was "remainded" by 0 (x % 0).
342RemainderByZero,
343/// Signed division overflowed (INT_MIN / -1).
344DivisionOverflow,
345/// Signed remainder overflowed (INT_MIN % -1).
346RemainderOverflow,
347/// Overflowing inbounds pointer arithmetic.
348PointerArithOverflow,
349/// Overflow in arithmetic that may not overflow.
350ArithOverflow { intrinsic: Symbol },
351/// Shift by too much.
352ShiftOverflow { intrinsic: Symbol, shift_amount: Either<u128, i128> },
353/// Invalid metadata in a wide pointer
354InvalidMeta(InvalidMetaKind),
355/// Reading a C string that does not end within its allocation.
356UnterminatedCString(Pointer<AllocId>),
357/// Using a pointer after it got freed.
358PointerUseAfterFree(AllocId, CheckInAllocMsg),
359/// Used a pointer outside the bounds it is valid for.
360PointerOutOfBounds {
361 alloc_id: AllocId,
362 alloc_size: Size,
363 ptr_offset: i64,
364/// The size of the memory range that was expected to be in-bounds.
365inbounds_size: i64,
366 msg: CheckInAllocMsg,
367 },
368/// Using an integer as a pointer in the wrong way.
369DanglingIntPointer {
370 addr: u64,
371/// The size of the memory range that was expected to be in-bounds (or 0 if we need an
372 /// allocation but not any actual memory there, e.g. for function pointers).
373inbounds_size: i64,
374 msg: CheckInAllocMsg,
375 },
376/// Used a pointer with bad alignment.
377AlignmentCheckFailed(Misalignment, CheckAlignMsg),
378/// Writing to read-only memory.
379WriteToReadOnly(AllocId),
380/// Trying to access the data behind a function pointer.
381DerefFunctionPointer(AllocId),
382/// Trying to access the data behind a vtable pointer.
383DerefVTablePointer(AllocId),
384/// Trying to access the data behind a va_list pointer.
385DerefVaListPointer(AllocId),
386/// Trying to access the actual type id.
387DerefTypeIdPointer(AllocId),
388/// Using a non-boolean `u8` as bool.
389InvalidBool(u8),
390/// Using a non-character `u32` as character.
391InvalidChar(u32),
392/// The tag of an enum does not encode an actual discriminant.
393InvalidTag(Scalar<AllocId>),
394/// Using a pointer-not-to-a-function as function pointer.
395InvalidFunctionPointer(Pointer<AllocId>),
396/// Using a pointer-not-to-a-va-list as variable argument list pointer.
397InvalidVaListPointer(Pointer<AllocId>),
398/// Using a pointer-not-to-a-vtable as vtable pointer.
399InvalidVTablePointer(Pointer<Option<AllocId>>),
400/// Using a vtable for the wrong trait.
401InvalidVTableTrait {
402/// The vtable that was actually referenced by the wide pointer metadata.
403vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
404/// The vtable that was expected at the point in MIR that it was accessed.
405expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
406 },
407/// Using a string that is not valid UTF-8,
408InvalidStr(std::str::Utf8Error),
409/// Using uninitialized data where it is not allowed.
410InvalidUninitBytes(Option<(AllocId, BadBytesAccess)>),
411/// Working with a local that is not currently live.
412DeadLocal,
413/// A discriminant of an uninhabited enum variant is written.
414UninhabitedEnumVariantWritten(VariantIdx),
415/// An uninhabited enum variant is projected.
416UninhabitedEnumVariantRead(Option<VariantIdx>),
417/// Trying to set discriminant to the niched variant, but the value does not match.
418InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
419/// ABI-incompatible argument types.
420AbiMismatchArgument {
421/// The index of the argument whose type is wrong.
422arg_idx: usize,
423 caller_ty: Ty<'tcx>,
424 callee_ty: Ty<'tcx>,
425 },
426/// ABI-incompatible return types.
427AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
428/// `va_arg` was called on an exhausted `VaList`.
429VaArgOutOfBounds,
430/// The caller and callee disagree on whether they are c-variadic or not.
431CVariadicMismatch { caller_is_c_variadic: bool, callee_is_c_variadic: bool },
432/// The caller and callee disagree on the number of fixed (i.e. non-c-variadic) arguments.
433CVariadicFixedCountMismatch { caller: u32, callee: u32 },
434}
435436impl<'tcx> fmt::Displayfor UndefinedBehaviorInfo<'tcx> {
437fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438use UndefinedBehaviorInfo::*;
439440fn fmt_in_alloc_attempt(
441 f: &mut fmt::Formatter<'_>,
442 msg: CheckInAllocMsg,
443 inbounds_size: i64,
444 ) -> fmt::Result {
445let inbounds_size_fmt = if inbounds_size == 1 {
446format_args!("1 byte")format_args!("1 byte")447 } else {
448format_args!("{0} bytes", inbounds_size)format_args!("{inbounds_size} bytes")449 };
450f.write_fmt(format_args!("{0}: ", msg))write!(f, "{msg}: ")?;
451match msg {
452 CheckInAllocMsg::MemoryAccess => {
453f.write_fmt(format_args!("attempting to access {0}", inbounds_size_fmt))write!(f, "attempting to access {inbounds_size_fmt}")454 }
455 CheckInAllocMsg::InboundsPointerArithmetic => {
456f.write_fmt(format_args!("attempting to offset pointer by {0}",
inbounds_size_fmt))write!(f, "attempting to offset pointer by {inbounds_size_fmt}")457 }
458 CheckInAllocMsg::Dereferenceable(what) if inbounds_size == 0 => {
459f.write_fmt(format_args!("{0} must point to some allocation", what))write!(f, "{what} must point to some allocation")460 }
461 CheckInAllocMsg::Dereferenceable(what) => {
462f.write_fmt(format_args!("{0} must be dereferenceable for {1}", what,
inbounds_size_fmt))write!(f, "{what} must be dereferenceable for {inbounds_size_fmt}")463 }
464 }
465 }
466467match self {
468Ub(msg) => f.write_fmt(format_args!("{0}", msg))write!(f, "{msg}"),
469470ValidationError { orig_ty, path: None, msg, .. } => {
471f.write_fmt(format_args!("constructing invalid value of type {0}: {1}",
orig_ty, msg))write!(f, "constructing invalid value of type {orig_ty}: {msg}")472 }
473ValidationError { orig_ty, path: Some(path), msg, .. } => {
474f.write_fmt(format_args!("constructing invalid value of type {0}: at {1}, {2}",
orig_ty, path, msg))write!(f, "constructing invalid value of type {orig_ty}: at {path}, {msg}")475 }
476477Unreachable => f.write_fmt(format_args!("entering unreachable code"))write!(f, "entering unreachable code"),
478BoundsCheckFailed { len, index } => {
479f.write_fmt(format_args!("indexing out of bounds: the len is {0} but the index is {1}",
len, index))write!(f, "indexing out of bounds: the len is {len} but the index is {index}")480 }
481DivisionByZero => f.write_fmt(format_args!("dividing by zero"))write!(f, "dividing by zero"),
482RemainderByZero => f.write_fmt(format_args!("calculating the remainder with a divisor of zero"))write!(f, "calculating the remainder with a divisor of zero"),
483DivisionOverflow => f.write_fmt(format_args!("overflow in signed division (dividing MIN by -1)"))write!(f, "overflow in signed division (dividing MIN by -1)"),
484RemainderOverflow => f.write_fmt(format_args!("overflow in signed remainder (dividing MIN by -1)"))write!(f, "overflow in signed remainder (dividing MIN by -1)"),
485PointerArithOverflow => f.write_fmt(format_args!("overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`"))write!(
486f,
487"overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`"
488),
489ArithOverflow { intrinsic } => f.write_fmt(format_args!("arithmetic overflow in `{0}`", intrinsic))write!(f, "arithmetic overflow in `{intrinsic}`"),
490ShiftOverflow { shift_amount, intrinsic } => {
491f.write_fmt(format_args!("overflowing shift by {0} in `{1}`", shift_amount,
intrinsic))write!(f, "overflowing shift by {shift_amount} in `{intrinsic}`")492 }
493InvalidMeta(InvalidMetaKind::SliceTooBig) => f.write_fmt(format_args!("invalid metadata in wide pointer: slice is bigger than largest supported object"))write!(
494f,
495"invalid metadata in wide pointer: slice is bigger than largest supported object"
496),
497InvalidMeta(InvalidMetaKind::TooBig) => f.write_fmt(format_args!("invalid metadata in wide pointer: total size is bigger than largest supported object"))write!(
498f,
499"invalid metadata in wide pointer: total size is bigger than largest supported object"
500),
501UnterminatedCString(ptr) => f.write_fmt(format_args!("reading a null-terminated string starting at {0} with no null found before end of allocation",
ptr))write!(
502f,
503"reading a null-terminated string starting at {ptr} with no null found before end of allocation"
504),
505PointerUseAfterFree(alloc_id, msg) => {
506f.write_fmt(format_args!("{0}: {1} has been freed, so this pointer is dangling",
msg, alloc_id))write!(f, "{msg}: {alloc_id} has been freed, so this pointer is dangling")507 }
508&PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
509 fmt_in_alloc_attempt(f, msg, inbounds_size)?;
510f.write_fmt(format_args!(", but got "))write!(f, ", but got ")?;
511// Write pointer. Offset might be negative so we cannot use the normal `impl Display
512 // for Pointer`.
513f.write_fmt(format_args!("{0}", alloc_id))write!(f, "{}", alloc_id)?;
514if ptr_offset > 0 {
515f.write_fmt(format_args!("+{0:#x}", ptr_offset))write!(f, "+{:#x}", ptr_offset)?;
516 } else if ptr_offset < 0 {
517f.write_fmt(format_args!("-{0:#x}", ptr_offset.unsigned_abs()))write!(f, "-{:#x}", ptr_offset.unsigned_abs())?;
518 }
519// Write why it is invalid.
520f.write_fmt(format_args!(" which "))write!(f, " which ")?;
521if ptr_offset < 0 {
522f.write_fmt(format_args!("points to before the beginning of the allocation"))write!(f, "points to before the beginning of the allocation")523 } else if inbounds_size < 0 {
524// We expected the ptr to have memory to its left, but it does not.
525if ptr_offset == 0 {
526f.write_fmt(format_args!("is at the beginning of the allocation"))write!(f, "is at the beginning of the allocation")527 } else {
528f.write_fmt(format_args!("is only {0} bytes from the beginning of the allocation",
ptr_offset))write!(f, "is only {ptr_offset} bytes from the beginning of the allocation")529 }
530 } else {
531let ptr_offset = ptr_offsetas u64;
532let alloc_size = alloc_size.bytes();
533if ptr_offset >= alloc_size {
534let size = if alloc_size == 1 {
535format_args!("1 byte")format_args!("1 byte")536 } else {
537format_args!("{0} bytes", alloc_size)format_args!("{alloc_size} bytes")538 };
539f.write_fmt(format_args!("is at or beyond the end of the allocation of size {0}",
size))write!(f, "is at or beyond the end of the allocation of size {size}",)540 } else {
541let dist_to_end = alloc_size - ptr_offset;
542let dist = if dist_to_end == 1 {
543format_args!("1 byte")format_args!("1 byte")544 } else {
545format_args!("{0} bytes", dist_to_end)format_args!("{dist_to_end} bytes")546 };
547f.write_fmt(format_args!("is only {0} from the end of the allocation", dist))write!(f, "is only {dist} from the end of the allocation",)548 }
549 }
550 }
551&DanglingIntPointer { addr: 0, inbounds_size, msg } => {
552 fmt_in_alloc_attempt(f, msg, inbounds_size)?;
553f.write_fmt(format_args!(", but got null pointer"))write!(f, ", but got null pointer")554 }
555&DanglingIntPointer { addr, inbounds_size, msg } => {
556 fmt_in_alloc_attempt(f, msg, inbounds_size)?;
557f.write_fmt(format_args!(", but got {0} which is a dangling pointer (it has no provenance)",
Pointer::<Option<CtfeProvenance>>::without_provenance(addr)))write!(
558f,
559", but got {ptr} which is a dangling pointer (it has no provenance)",
560 ptr = Pointer::<Option<CtfeProvenance>>::without_provenance(addr),
561 )562 }
563AlignmentCheckFailed(misalign, msg) => {
564f.write_fmt(format_args!("{0} with alignment {1}, but alignment {2} is required",
match msg {
CheckAlignMsg::AccessedPtr => "accessing memory",
CheckAlignMsg::BasedOn => "accessing memory based on pointer",
}, misalign.has.bytes(), misalign.required.bytes()))write!(
565f,
566"{acc} with alignment {has}, but alignment {required} is required",
567 acc = match msg {
568 CheckAlignMsg::AccessedPtr => "accessing memory",
569 CheckAlignMsg::BasedOn => "accessing memory based on pointer",
570 },
571 has = misalign.has.bytes(),
572 required = misalign.required.bytes(),
573 )574 }
575WriteToReadOnly(alloc) => f.write_fmt(format_args!("writing to {0} which is read-only", alloc))write!(f, "writing to {alloc} which is read-only"),
576DerefFunctionPointer(alloc) => {
577f.write_fmt(format_args!("accessing {0} which contains a function", alloc))write!(f, "accessing {alloc} which contains a function")578 }
579DerefVTablePointer(alloc) => f.write_fmt(format_args!("accessing {0} which contains a vtable", alloc))write!(f, "accessing {alloc} which contains a vtable"),
580DerefVaListPointer(alloc) => {
581f.write_fmt(format_args!("accessing {0} which contains a variable argument list",
alloc))write!(f, "accessing {alloc} which contains a variable argument list")582 }
583DerefTypeIdPointer(alloc) => f.write_fmt(format_args!("accessing {0} which contains a `TypeId`", alloc))write!(f, "accessing {alloc} which contains a `TypeId`"),
584InvalidBool(value) => {
585f.write_fmt(format_args!("interpreting an invalid 8-bit value as a bool: 0x{0:02x}",
value))write!(f, "interpreting an invalid 8-bit value as a bool: 0x{value:02x}")586 }
587InvalidChar(value) => {
588f.write_fmt(format_args!("interpreting an invalid 32-bit value as a char: 0x{0:08x}",
value))write!(f, "interpreting an invalid 32-bit value as a char: 0x{value:08x}")589 }
590InvalidTag(tag) => f.write_fmt(format_args!("enum value has invalid tag: {0:x}", tag))write!(f, "enum value has invalid tag: {tag:x}"),
591InvalidFunctionPointer(ptr) => {
592f.write_fmt(format_args!("using {0} as function pointer but it does not point to a function",
ptr))write!(f, "using {ptr} as function pointer but it does not point to a function")593 }
594InvalidVaListPointer(ptr) => f.write_fmt(format_args!("using {0} as variable argument list pointer but it does not point to a variable argument list",
ptr))write!(
595f,
596"using {ptr} as variable argument list pointer but it does not point to a variable argument list"
597),
598InvalidVTablePointer(ptr) => {
599f.write_fmt(format_args!("using {0} as vtable pointer but it does not point to a vtable",
ptr))write!(f, "using {ptr} as vtable pointer but it does not point to a vtable")600 }
601InvalidVTableTrait { vtable_dyn_type, expected_dyn_type } => f.write_fmt(format_args!("using vtable for `{0}` but `{1}` was expected",
vtable_dyn_type, expected_dyn_type))write!(
602f,
603"using vtable for `{vtable_dyn_type}` but `{expected_dyn_type}` was expected"
604),
605InvalidStr(err) => f.write_fmt(format_args!("this string is not valid UTF-8: {0}", err))write!(f, "this string is not valid UTF-8: {err}"),
606InvalidUninitBytes(None) => {
607f.write_fmt(format_args!("using uninitialized data, but this operation requires initialized memory"))write!(
608f,
609"using uninitialized data, but this operation requires initialized memory"
610)611 }
612InvalidUninitBytes(Some((alloc, info))) => f.write_fmt(format_args!("reading memory at {2}{0}, but memory is uninitialized at {1}, and this operation requires initialized memory",
info.access, info.bad, alloc))write!(
613f,
614"reading memory at {alloc}{access}, but memory is uninitialized at {uninit}, and this operation requires initialized memory",
615 access = info.access,
616 uninit = info.bad,
617 ),
618DeadLocal => f.write_fmt(format_args!("accessing a dead local variable"))write!(f, "accessing a dead local variable"),
619UninhabitedEnumVariantWritten(_) => {
620f.write_fmt(format_args!("writing discriminant of an uninhabited enum variant"))write!(f, "writing discriminant of an uninhabited enum variant")621 }
622UninhabitedEnumVariantRead(_) => {
623f.write_fmt(format_args!("read discriminant of an uninhabited enum variant"))write!(f, "read discriminant of an uninhabited enum variant")624 }
625InvalidNichedEnumVariantWritten { enum_ty } => {
626f.write_fmt(format_args!("trying to set discriminant of a {0} to the niched variant, but the value does not match",
enum_ty))write!(
627f,
628"trying to set discriminant of a {enum_ty} to the niched variant, but the value does not match"
629)630 }
631AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => f.write_fmt(format_args!("calling a function whose parameter #{0} has type {1} passing argument of type {2}",
arg_idx + 1, callee_ty, caller_ty))write!(
632f,
633"calling a function whose parameter #{arg_idx} has type {callee_ty} passing argument of type {caller_ty}",
634 arg_idx = arg_idx + 1, // adjust for 1-indexed lists in output
635),
636AbiMismatchReturn { caller_ty, callee_ty } => f.write_fmt(format_args!("calling a function with return type {0} passing return place of type {1}",
callee_ty, caller_ty))write!(
637f,
638"calling a function with return type {callee_ty} passing return place of type {caller_ty}"
639),
640VaArgOutOfBounds => f.write_fmt(format_args!("more C-variadic arguments read than were passed"))write!(f, "more C-variadic arguments read than were passed"),
641CVariadicMismatch { .. } => f.write_fmt(format_args!("calling a function where the caller and callee disagree on whether the function is C-variadic"))write!(
642f,
643"calling a function where the caller and callee disagree on whether the function is C-variadic"
644),
645CVariadicFixedCountMismatch { caller, callee } => f.write_fmt(format_args!("calling a C-variadic function with {0} fixed arguments, but the function expects {1}",
caller, callee))write!(
646f,
647"calling a C-variadic function with {caller} fixed arguments, but the function expects {callee}"
648),
649 }
650 }
651}
652653/// Error information for when the program we executed turned out not to actually be a valid
654/// program. This cannot happen in stand-alone Miri (except for layout errors that are only detect
655/// during monomorphization), but it can happen during CTFE/ConstProp where we work on generic code
656/// or execution does not have all information available.
657#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InvalidProgramInfo<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
InvalidProgramInfo::TooGeneric =>
::core::fmt::Formatter::write_str(f, "TooGeneric"),
InvalidProgramInfo::AlreadyReported(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AlreadyReported", &__self_0),
InvalidProgramInfo::Layout(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Layout",
&__self_0),
}
}
}Debug)]
658pub enum InvalidProgramInfo<'tcx> {
659/// Resolution can fail if we are in a too generic context.
660TooGeneric,
661/// Abort in case errors are already reported.
662AlreadyReported(ReportedErrorInfo),
663/// An error occurred during layout computation.
664Layout(layout::LayoutError<'tcx>),
665}
666667impl<'tcx> fmt::Displayfor InvalidProgramInfo<'tcx> {
668fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
669use InvalidProgramInfo::*;
670match self {
671TooGeneric => f.write_fmt(format_args!("encountered overly generic constant"))write!(f, "encountered overly generic constant"),
672AlreadyReported(_) => {
673f.write_fmt(format_args!("an error has already been reported elsewhere (this should not usually be printed)"))write!(
674f,
675"an error has already been reported elsewhere (this should not usually be printed)"
676)677 }
678Layout(e) => f.write_fmt(format_args!("{0}", e))write!(f, "{e}"),
679 }
680 }
681}
682683/// Error information for when the program did something that might (or might not) be correct
684/// to do according to the Rust spec, but due to limitations in the interpreter, the
685/// operation could not be carried out. These limitations can differ between CTFE and the
686/// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
687#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UnsupportedOpInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
UnsupportedOpInfo::Unsupported(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Unsupported", &__self_0),
UnsupportedOpInfo::UnsizedLocal =>
::core::fmt::Formatter::write_str(f, "UnsizedLocal"),
UnsupportedOpInfo::ExternTypeField =>
::core::fmt::Formatter::write_str(f, "ExternTypeField"),
UnsupportedOpInfo::ReadPartialPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ReadPartialPointer", &__self_0),
UnsupportedOpInfo::ReadPointerAsInt(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ReadPointerAsInt", &__self_0),
UnsupportedOpInfo::ThreadLocalStatic(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ThreadLocalStatic", &__self_0),
UnsupportedOpInfo::ExternStatic(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ExternStatic", &__self_0),
}
}
}Debug)]
688pub enum UnsupportedOpInfo {
689/// Free-form case. Only for errors that are never caught! Used by Miri.
690// FIXME still use translatable diagnostics
691Unsupported(String),
692/// Unsized local variables.
693UnsizedLocal,
694/// Extern type field with an indeterminate offset.
695ExternTypeField,
696//
697 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
698 //
699/// Attempting to read or copy parts of a pointer to somewhere else; without knowing absolute
700 /// addresses, the resulting state cannot be represented by the CTFE interpreter.
701ReadPartialPointer(Pointer<AllocId>),
702/// Encountered a pointer where we needed an integer.
703ReadPointerAsInt(Option<(AllocId, BadBytesAccess)>),
704/// Accessing thread local statics
705ThreadLocalStatic(DefId),
706/// Accessing an unsupported extern static.
707ExternStatic(DefId),
708}
709710impl fmt::Displayfor UnsupportedOpInfo {
711fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
712use UnsupportedOpInfo::*;
713match self {
714Unsupported(s) => f.write_fmt(format_args!("{0}", s))write!(f, "{s}"),
715ExternTypeField => {
716f.write_fmt(format_args!("`extern type` field does not have a known offset"))write!(f, "`extern type` field does not have a known offset")717 }
718UnsizedLocal => f.write_fmt(format_args!("unsized locals are not supported"))write!(f, "unsized locals are not supported"),
719ReadPartialPointer(ptr) => {
720f.write_fmt(format_args!("unable to read parts of a pointer from memory at {0}",
ptr))write!(f, "unable to read parts of a pointer from memory at {ptr}")721 }
722ReadPointerAsInt(_) => f.write_fmt(format_args!("unable to turn pointer into integer"))write!(f, "unable to turn pointer into integer"),
723&ThreadLocalStatic(did) => {
724f.write_fmt(format_args!("cannot access thread local static `{0}`",
ty::tls::with(|tcx| tcx.def_path_str(did))))write!(
725f,
726"cannot access thread local static `{did}`",
727 did = ty::tls::with(|tcx| tcx.def_path_str(did))
728 )729 }
730&ExternStatic(did) => {
731f.write_fmt(format_args!("cannot access extern static `{0}`",
ty::tls::with(|tcx| tcx.def_path_str(did))))write!(
732f,
733"cannot access extern static `{did}`",
734 did = ty::tls::with(|tcx| tcx.def_path_str(did))
735 )736 }
737 }
738 }
739}
740741/// Error information for when the program exhausted the resources granted to it
742/// by the interpreter.
743#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ResourceExhaustionInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ResourceExhaustionInfo::StackFrameLimitReached =>
"StackFrameLimitReached",
ResourceExhaustionInfo::MemoryExhausted => "MemoryExhausted",
ResourceExhaustionInfo::AddressSpaceFull =>
"AddressSpaceFull",
ResourceExhaustionInfo::Interrupted => "Interrupted",
})
}
}Debug)]
744pub enum ResourceExhaustionInfo {
745/// The stack grew too big.
746StackFrameLimitReached,
747/// There is not enough memory (on the host) to perform an allocation.
748MemoryExhausted,
749/// The address space (of the target) is full.
750AddressSpaceFull,
751/// The compiler got an interrupt signal (a user ran out of patience).
752Interrupted,
753}
754755impl fmt::Displayfor ResourceExhaustionInfo {
756fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757use ResourceExhaustionInfo::*;
758match self {
759StackFrameLimitReached => {
760f.write_fmt(format_args!("reached the configured maximum number of stack frames"))write!(f, "reached the configured maximum number of stack frames")761 }
762MemoryExhausted => {
763f.write_fmt(format_args!("tried to allocate more memory than available to compiler"))write!(f, "tried to allocate more memory than available to compiler")764 }
765AddressSpaceFull => {
766f.write_fmt(format_args!("there are no more free addresses in the address space"))write!(f, "there are no more free addresses in the address space")767 }
768Interrupted => f.write_fmt(format_args!("compilation was interrupted"))write!(f, "compilation was interrupted"),
769 }
770 }
771}
772773/// A trait for machine-specific errors (or other "machine stop" conditions).
774pub trait MachineStopType: Any + fmt::Display + fmt::Debug + Send {
775/// This error occurred during validation, inside a value at the given path.
776fn with_validation_path(&mut self, _path: String) {}
777}
778779impl dyn MachineStopType {
780#[inline(always)]
781pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
782let x: &dyn Any = self;
783x.downcast_ref()
784 }
785}
786787#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InterpErrorKind<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
InterpErrorKind::UndefinedBehavior(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"UndefinedBehavior", &__self_0),
InterpErrorKind::InvalidProgram(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidProgram", &__self_0),
InterpErrorKind::Unsupported(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Unsupported", &__self_0),
InterpErrorKind::ResourceExhaustion(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ResourceExhaustion", &__self_0),
InterpErrorKind::MachineStop(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MachineStop", &__self_0),
}
}
}Debug)]
788pub enum InterpErrorKind<'tcx> {
789/// The program caused undefined behavior.
790UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
791/// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
792InvalidProgram(InvalidProgramInfo<'tcx>),
793/// The program did something the interpreter does not support (some of these *might* be UB
794 /// but the interpreter is not sure).
795Unsupported(UnsupportedOpInfo),
796/// The program exhausted the interpreter's resources (stack/heap too big,
797 /// execution takes too long, ...).
798ResourceExhaustion(ResourceExhaustionInfo),
799/// Stop execution for a machine-controlled reason. This is never raised by
800 /// the core engine itself.
801MachineStop(Box<dyn MachineStopType>),
802}
803804impl<'tcx> fmt::Displayfor InterpErrorKind<'tcx> {
805fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806use InterpErrorKind::*;
807match self {
808Unsupported(msg) => f.write_fmt(format_args!("{0}", msg))write!(f, "{msg}"),
809InvalidProgram(msg) => f.write_fmt(format_args!("{0}", msg))write!(f, "{msg}"),
810UndefinedBehavior(msg) => f.write_fmt(format_args!("{0}", msg))write!(f, "{msg}"),
811ResourceExhaustion(msg) => f.write_fmt(format_args!("{0}", msg))write!(f, "{msg}"),
812MachineStop(msg) => f.write_fmt(format_args!("{0}", msg))write!(f, "{msg}"),
813 }
814 }
815}
816817impl InterpErrorKind<'_> {
818/// Some errors do string formatting even if the error is never printed.
819 /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
820 /// so this method lets us detect them and `bug!` on unexpected errors.
821pub fn formatted_string(&self) -> bool {
822#[allow(non_exhaustive_omitted_patterns)] match self {
InterpErrorKind::Unsupported(UnsupportedOpInfo::Unsupported(_)) |
InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError {
.. }) |
InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) =>
true,
_ => false,
}matches!(
823self,
824 InterpErrorKind::Unsupported(UnsupportedOpInfo::Unsupported(_))
825 | InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. })
826 | InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
827 )828 }
829}
830831// Macros for constructing / throwing `InterpErrorKind`
832#[macro_export]
833macro_rules!err_unsup {
834 ($($tt:tt)*) => {
835$crate::mir::interpret::InterpErrorKind::Unsupported(
836$crate::mir::interpret::UnsupportedOpInfo::$($tt)*
837 )
838 };
839}
840841#[macro_export]
842macro_rules!err_unsup_format {
843 ($($tt:tt)*) => { $crate::err_unsup!(Unsupported(format!($($tt)*))) };
844}
845846#[macro_export]
847macro_rules!err_inval {
848 ($($tt:tt)*) => {
849$crate::mir::interpret::InterpErrorKind::InvalidProgram(
850$crate::mir::interpret::InvalidProgramInfo::$($tt)*
851 )
852 };
853}
854855#[macro_export]
856macro_rules!err_ub {
857 ($($tt:tt)*) => {
858$crate::mir::interpret::InterpErrorKind::UndefinedBehavior(
859$crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
860 )
861 };
862}
863864#[macro_export]
865macro_rules!err_ub_format {
866 ($($tt:tt)*) => { $crate::err_ub!(Ub(format!($($tt)*))) };
867}
868869#[macro_export]
870macro_rules!err_exhaust {
871 ($($tt:tt)*) => {
872$crate::mir::interpret::InterpErrorKind::ResourceExhaustion(
873$crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
874 )
875 };
876}
877878#[macro_export]
879macro_rules!err_machine_stop {
880 ($($tt:tt)*) => {
881$crate::mir::interpret::InterpErrorKind::MachineStop(Box::new($($tt)*))
882 };
883}
884885// In the `throw_*` macros, avoid `return` to make them work with `try {}`.
886#[macro_export]
887macro_rules!throw_unsup {
888 ($($tt:tt)*) => { do yeet $crate::err_unsup!($($tt)*) };
889}
890891#[macro_export]
892macro_rules!throw_unsup_format {
893 ($($tt:tt)*) => { do yeet $crate::err_unsup_format!($($tt)*) };
894}
895896#[macro_export]
897macro_rules!throw_inval {
898 ($($tt:tt)*) => { do yeet $crate::err_inval!($($tt)*) };
899}
900901#[macro_export]
902macro_rules!throw_ub {
903 ($($tt:tt)*) => { do yeet $crate::err_ub!($($tt)*) };
904}
905906#[macro_export]
907macro_rules!throw_ub_format {
908 ($($tt:tt)*) => { do yeet $crate::err_ub_format!($($tt)*) };
909}
910911#[macro_export]
912macro_rules!throw_exhaust {
913 ($($tt:tt)*) => { do yeet $crate::err_exhaust!($($tt)*) };
914}
915916#[macro_export]
917macro_rules!throw_machine_stop {
918 ($($tt:tt)*) => { do yeet $crate::err_machine_stop!($($tt)*) };
919}
920921/// Guard type that panics on drop.
922#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Guard {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Guard")
}
}Debug)]
923struct Guard;
924925impl Dropfor Guard {
926fn drop(&mut self) {
927// We silence the guard if we are already panicking, to avoid double-panics.
928if !std::thread::panicking() {
929{
::core::panicking::panic_fmt(format_args!("an interpreter error got improperly discarded; use `discard_err()` if this is intentional"));
};panic!(
930"an interpreter error got improperly discarded; use `discard_err()` if this is intentional"
931);
932 }
933 }
934}
935936/// The result type used by the interpreter. This is a newtype around `Result`
937/// to block access to operations like `ok()` that discard UB errors.
938///
939/// We also make things panic if this type is ever implicitly dropped.
940#[derive(#[automatically_derived]
impl<'tcx, T: ::core::fmt::Debug> ::core::fmt::Debug for InterpResult<'tcx, T>
{
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "InterpResult",
"res", &self.res, "guard", &&self.guard)
}
}Debug)]
941#[must_use]
942pub struct InterpResult<'tcx, T = ()> {
943 res: Result<T, InterpErrorInfo<'tcx>>,
944 guard: Guard,
945}
946947impl<'tcx, T> ops::Tryfor InterpResult<'tcx, T> {
948type Output = T;
949type Residual = InterpResult<'tcx, convert::Infallible>;
950951#[inline]
952fn from_output(output: Self::Output) -> Self {
953InterpResult::new(Ok(output))
954 }
955956#[inline]
957fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
958match self.disarm() {
959Ok(v) => ops::ControlFlow::Continue(v),
960Err(e) => ops::ControlFlow::Break(InterpResult::new(Err(e))),
961 }
962 }
963}
964965impl<'tcx, T> ops::Residual<T> for InterpResult<'tcx, convert::Infallible> {
966type TryType = InterpResult<'tcx, T>;
967}
968969impl<'tcx, T> ops::FromResidualfor InterpResult<'tcx, T> {
970#[inline]
971 #[track_caller]
972fn from_residual(residual: InterpResult<'tcx, convert::Infallible>) -> Self {
973match residual.disarm() {
974Err(e) => Self::new(Err(e)),
975 }
976 }
977}
978979// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`.
980impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult<'tcx, T> {
981#[inline]
982fn from_residual(ops::Yeet(e): ops::Yeet<InterpErrorKind<'tcx>>) -> Self {
983Self::new(Err(e.into()))
984 }
985}
986987// Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`.
988// This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`.
989impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> ops::FromResidual<Result<convert::Infallible, E>>
990for InterpResult<'tcx, T>
991{
992#[inline]
993fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
994match residual {
995Err(e) => Self::new(Err(e.into())),
996 }
997 }
998}
9991000impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> From<Result<T, E>> for InterpResult<'tcx, T> {
1001#[inline]
1002fn from(value: Result<T, E>) -> Self {
1003Self::new(value.map_err(|e| e.into()))
1004 }
1005}
10061007impl<'tcx, T, V: FromIterator<T>> FromIterator<InterpResult<'tcx, T>> for InterpResult<'tcx, V> {
1008fn from_iter<I: IntoIterator<Item = InterpResult<'tcx, T>>>(iter: I) -> Self {
1009Self::new(iter.into_iter().map(|x| x.disarm()).collect())
1010 }
1011}
10121013impl<'tcx, T> InterpResult<'tcx, T> {
1014#[inline(always)]
1015fn new(res: Result<T, InterpErrorInfo<'tcx>>) -> Self {
1016Self { res, guard: Guard }
1017 }
10181019#[inline(always)]
1020fn disarm(self) -> Result<T, InterpErrorInfo<'tcx>> {
1021 mem::forget(self.guard);
1022self.res
1023 }
10241025/// Discard the error information in this result. Only use this if ignoring Undefined Behavior is okay!
1026#[inline]
1027pub fn discard_err(self) -> Option<T> {
1028self.disarm().ok()
1029 }
10301031/// Look at the `Result` wrapped inside of this.
1032 /// Must only be used to report the error!
1033#[inline]
1034pub fn report_err(self) -> Result<T, InterpErrorInfo<'tcx>> {
1035self.disarm()
1036 }
10371038#[inline]
1039pub fn map<U>(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> {
1040InterpResult::new(self.disarm().map(f))
1041 }
10421043#[inline]
1044pub fn map_err_kind(
1045self,
1046 f: impl FnOnce(InterpErrorKind<'tcx>) -> InterpErrorKind<'tcx>,
1047 ) -> InterpResult<'tcx, T> {
1048InterpResult::new(self.disarm().map_err(|mut e| {
1049e.0.kind = f(e.0.kind);
1050e1051 }))
1052 }
10531054#[inline]
1055pub fn inspect_err_info(self, f: impl FnOnce(&InterpErrorInfo<'tcx>)) -> InterpResult<'tcx, T> {
1056InterpResult::new(self.disarm().inspect_err(f))
1057 }
10581059#[inline]
1060 #[track_caller]
1061pub fn unwrap(self) -> T {
1062self.disarm().unwrap()
1063 }
10641065#[inline]
1066 #[track_caller]
1067pub fn unwrap_or_else(self, f: impl FnOnce(InterpErrorInfo<'tcx>) -> T) -> T {
1068self.disarm().unwrap_or_else(f)
1069 }
10701071#[inline]
1072 #[track_caller]
1073pub fn expect(self, msg: &str) -> T {
1074self.disarm().expect(msg)
1075 }
10761077#[inline]
1078pub fn and_then<U>(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> {
1079InterpResult::new(self.disarm().and_then(|t| f(t).disarm()))
1080 }
10811082/// Returns success if both `self` and `other` succeed, while ensuring we don't
1083 /// accidentally drop an error.
1084 ///
1085 /// If both are an error, `self` will be reported.
1086#[inline]
1087pub fn and<U>(self, other: InterpResult<'tcx, U>) -> InterpResult<'tcx, (T, U)> {
1088match self.disarm() {
1089Ok(t) => interp_ok((t, other?)),
1090Err(e) => {
1091// Discard the other error.
1092drop(other.disarm());
1093// Return `self`.
1094InterpResult::new(Err(e))
1095 }
1096 }
1097 }
1098}
10991100#[inline(always)]
1101pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> {
1102InterpResult::new(Ok(x))
1103}