/// layout in memory of a fixed size array (for example, for unsafe
/// initialization).
///
-/// Note that the traits AsRef and AsMut provide similar methods for types that
+/// Note that the traits [`AsRef`] and [`AsMut`] provide similar methods for types that
/// may not be fixed-size arrays. Implementors should prefer those traits
/// instead.
+///
+/// [`AsRef`]: ../convert/trait.AsRef.html
+/// [`AsMut`]: ../convert/trait.AsMut.html
#[unstable(feature = "fixed_size_array", issue = "27778")]
pub unsafe trait FixedSizeArray<T> {
/// Converts the array to immutable slice
/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
/// is implemented and cannot fail -- the associated `Error` type for
/// calling `T::try_from()` on a value of type `T` is [`Infallible`].
-/// When the [`!`] type is stablized [`Infallible`] and [`!`] will be
+/// When the [`!`] type is stabilized [`Infallible`] and [`!`] will be
/// equivalent.
///
/// `TryFrom<T>` can be implemented as follows:
/// final value. This method does not block if the value is not ready. Instead,
/// the current task is scheduled to be woken up when it's possible to make
/// further progress by `poll`ing again. The `context` passed to the `poll`
-/// method can provide a `Waker`, which is a handle for waking up the current
+/// method can provide a [`Waker`], which is a handle for waking up the current
/// task.
///
/// When using a future, you generally won't call `poll` directly, but instead
/// `.await` the value.
+///
+/// [`Waker`]: ../task/struct.Waker.html
#[doc(spotlight)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
/// use std::fmt::Write as FmtWrite;
/// use std::io::Write as IoWrite;
///
-/// let mut s = String::new();
-/// let mut v = Vec::new();
-/// write!(&mut s, "{} {}", "abc", 123).unwrap(); // uses fmt::Write::write_fmt
-/// write!(&mut v, "s = {:?}", s).unwrap(); // uses io::Write::write_fmt
-/// assert_eq!(v, b"s = \"abc 123\"");
+/// fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// let mut s = String::new();
+/// let mut v = Vec::new();
+///
+/// write!(&mut s, "{} {}", "abc", 123)?; // uses fmt::Write::write_fmt
+/// write!(&mut v, "s = {:?}", s)?; // uses io::Write::write_fmt
+/// assert_eq!(v, b"s = \"abc 123\"");
+/// Ok(())
+/// }
/// ```
///
/// Note: This macro can be used in `no_std` setups as well.
/// # Examples
///
/// ```
-/// use std::io::Write;
+/// use std::io::{Write, Result};
///
-/// let mut w = Vec::new();
-/// writeln!(&mut w).unwrap();
-/// writeln!(&mut w, "test").unwrap();
-/// writeln!(&mut w, "formatted {}", "arguments").unwrap();
+/// fn main() -> Result<()> {
+/// let mut w = Vec::new();
+/// writeln!(&mut w)?;
+/// writeln!(&mut w, "test")?;
+/// writeln!(&mut w, "formatted {}", "arguments")?;
///
-/// assert_eq!(&w[..], "\ntest\nformatted arguments\n".as_bytes());
+/// assert_eq!(&w[..], "\ntest\nformatted arguments\n".as_bytes());
+/// Ok(())
+/// }
/// ```
///
/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects
/// use std::fmt::Write as FmtWrite;
/// use std::io::Write as IoWrite;
///
-/// let mut s = String::new();
-/// let mut v = Vec::new();
-/// writeln!(&mut s, "{} {}", "abc", 123).unwrap(); // uses fmt::Write::write_fmt
-/// writeln!(&mut v, "s = {:?}", s).unwrap(); // uses io::Write::write_fmt
-/// assert_eq!(v, b"s = \"abc 123\\n\"\n");
+/// fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// let mut s = String::new();
+/// let mut v = Vec::new();
+///
+/// writeln!(&mut s, "{} {}", "abc", 123)?; // uses fmt::Write::write_fmt
+/// writeln!(&mut v, "s = {:?}", s)?; // uses io::Write::write_fmt
+/// assert_eq!(v, b"s = \"abc 123\\n\"\n");
+/// Ok(())
+/// }
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
/// Reads the value from the `MaybeUninit<T>` container. The resulting `T` is subject
/// to the usual drop handling.
///
- /// Whenever possible, it is preferrable to use [`assume_init`] instead, which
+ /// Whenever possible, it is preferable to use [`assume_init`] instead, which
/// prevents duplicating the content of the `MaybeUninit<T>`.
///
/// # Safety
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
/// used with the `add` method.
///
- /// There are no guarantees whatsover that offsetting the pointer will not overflow or go
+ /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
/// the returned offset is correct in all terms other than alignment.
///
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
/// used with the `add` method.
///
- /// There are no guarantees whatsover that offsetting the pointer will not overflow or go
+ /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
/// the returned offset is correct in all terms other than alignment.
///
const_var: &'tcx ty::Const<'tcx>
) -> &'tcx ty::Const<'tcx> {
let infcx = self.infcx.expect("encountered const-var without infcx");
- let bound_to = infcx.resolve_const_var(const_var);
+ let bound_to = infcx.shallow_resolve(const_var);
if bound_to != const_var {
self.fold_const(bound_to)
} else {
}
}
- pub fn resolve_const_var(
- &self,
- ct: &'tcx ty::Const<'tcx>
- ) -> &'tcx ty::Const<'tcx> {
- if let ty::Const { val: ConstValue::Infer(InferConst::Var(v)), .. } = ct {
- self.const_unification_table
- .borrow_mut()
- .probe_value(*v)
- .val
- .known()
- .map(|c| self.resolve_const_var(c))
- .unwrap_or(ct)
- } else {
- ct
- }
- }
-
pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> {
/*!
* Attempts to resolve all type/region/const variables in
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
// recursion. Note though that we prevent type
- // variables from unifyxing to other type variables
+ // variables from unifying to other type variables
// directly (though they may be embedded
// structurally), and we prevent cycles in any case,
// so this recursion should always be of very limited
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- match ct {
- ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => {
+ if let ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } = ct {
self.infcx.const_unification_table
.borrow_mut()
.probe_value(*vid)
.val
.known()
- .map(|c| self.fold_const(c))
.unwrap_or(ct)
- }
- _ => ct,
+ } else {
+ ct
}
}
}
{
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
let offset = ptr.offset.bytes() as usize;
- match self.bytes[offset..].iter().position(|&c| c == 0) {
+ Ok(match self.bytes[offset..].iter().position(|&c| c == 0) {
Some(size) => {
let size_with_null = Size::from_bytes((size + 1) as u64);
// Go through `get_bytes` for checks and AllocationExtra hooks.
// We read the null, so we include it in the request, but we want it removed
// from the result, so we do subslicing.
- Ok(&self.get_bytes(cx, ptr, size_with_null)?[..size])
+ &self.get_bytes(cx, ptr, size_with_null)?[..size]
}
// This includes the case where `offset` is out-of-bounds to begin with.
- None => err!(UnterminatedCString(ptr.erase_tag())),
- }
+ None => throw_unsup!(UnterminatedCString(ptr.erase_tag())),
+ })
}
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
if self.relocations(cx, ptr, size).is_empty() {
Ok(())
} else {
- err!(ReadPointerAsBytes)
+ throw_unsup!(ReadPointerAsBytes)
}
}
self.undef_mask.is_range_defined(
ptr.offset,
ptr.offset + size,
- ).or_else(|idx| err!(ReadUndefBytes(idx)))
+ ).or_else(|idx| throw_unsup!(ReadUndefBytes(idx)))
}
pub fn mark_definedness(
lint_root: Option<hir::HirId>,
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
match self.error {
- InterpError::Layout(LayoutError::Unknown(_)) |
- InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric),
- InterpError::Layout(LayoutError::SizeOverflow(_)) |
- InterpError::TypeckError => return Err(ErrorHandled::Reported),
+ err_inval!(Layout(LayoutError::Unknown(_))) |
+ err_inval!(TooGeneric) =>
+ return Err(ErrorHandled::TooGeneric),
+ err_inval!(Layout(LayoutError::SizeOverflow(_))) |
+ err_inval!(TypeckError) =>
+ return Err(ErrorHandled::Reported),
_ => {},
}
trace!("reporting const eval failure at {:?}", self.span);
/// Packages the kind of error we got from the const code interpreter
/// up with a Rust-level backtrace of where the error occured.
/// Thsese should always be constructed by calling `.into()` on
-/// a `InterpError`. In `librustc_mir::interpret`, we have the `err!`
-/// macro for this.
+/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
+/// macros for this.
#[derive(Debug, Clone)]
pub struct InterpErrorInfo<'tcx> {
pub kind: InterpError<'tcx>,
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub enum PanicMessage<O> {
+pub enum PanicInfo<O> {
Panic {
msg: Symbol,
line: u32,
}
/// Type for MIR `Assert` terminator error messages.
-pub type AssertMessage<'tcx> = PanicMessage<mir::Operand<'tcx>>;
+pub type AssertMessage<'tcx> = PanicInfo<mir::Operand<'tcx>>;
-impl<O> PanicMessage<O> {
+impl<O> PanicInfo<O> {
/// Getting a description does not require `O` to be printable, and does not
/// require allocation.
/// The caller is expected to handle `Panic` and `BoundsCheck` separately.
pub fn description(&self) -> &'static str {
- use PanicMessage::*;
+ use PanicInfo::*;
match self {
Overflow(mir::BinOp::Add) =>
"attempt to add with overflow",
GeneratorResumedAfterPanic =>
"generator resumed after panicking",
Panic { .. } | BoundsCheck { .. } =>
- bug!("Unexpected PanicMessage"),
+ bug!("Unexpected PanicInfo"),
}
}
}
-impl<O: fmt::Debug> fmt::Debug for PanicMessage<O> {
+impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use PanicMessage::*;
+ use PanicInfo::*;
match self {
Panic { ref msg, line, col, ref file } =>
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub enum InterpError<'tcx> {
- /// This variant is used by machines to signal their own errors that do not
- /// match an existing variant.
- MachineError(String),
+pub enum InvalidProgramInfo<'tcx> {
+ /// Resolution can fail if we are in a too generic context.
+ TooGeneric,
+ /// Cannot compute this constant because it depends on another one
+ /// which already produced an error.
+ ReferencedConstant,
+ /// Abort in case type errors are reached.
+ TypeckError,
+ /// An error occurred during layout computation.
+ Layout(layout::LayoutError<'tcx>),
+}
- /// Not actually an interpreter error -- used to signal that execution has exited
- /// with the given status code. Used by Miri, but not by CTFE.
- Exit(i32),
+impl fmt::Debug for InvalidProgramInfo<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use InvalidProgramInfo::*;
+ match self {
+ TooGeneric =>
+ write!(f, "encountered overly generic constant"),
+ ReferencedConstant =>
+ write!(f, "referenced constant has errors"),
+ TypeckError =>
+ write!(f, "encountered constants with type errors, stopping evaluation"),
+ Layout(ref err) =>
+ write!(f, "rustc layout computation failed: {:?}", err),
+ }
+ }
+}
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum UndefinedBehaviourInfo {
+ /// Handle cases which for which we do not have a fixed variant.
+ Ub(String),
+ /// Unreachable code was executed.
+ Unreachable,
+}
+
+impl fmt::Debug for UndefinedBehaviourInfo {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use UndefinedBehaviourInfo::*;
+ match self {
+ Ub(ref msg) =>
+ write!(f, "{}", msg),
+ Unreachable =>
+ write!(f, "entered unreachable code"),
+ }
+ }
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum UnsupportedOpInfo<'tcx> {
+ /// Handle cases which for which we do not have a fixed variant.
+ Unimplemented(String),
+
+ // -- Everything below is not classified yet --
FunctionAbiMismatch(Abi, Abi),
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionArgCountMismatch,
- NoMirFor(String),
UnterminatedCString(Pointer),
DanglingPointerDeref,
DoubleFree,
ReadUndefBytes(Size),
DeadLocal,
InvalidBoolOp(mir::BinOp),
- Unimplemented(String),
+ InlineAsm,
+ UnimplementedTraitSelection,
+ CalledClosureAsFunction,
+ NoMirFor(String),
+ /// This variant is used by machines to signal their own errors that do not
+ /// match an existing variant.
+ MachineError(String),
DerefFunctionPointer,
ExecuteMemory,
Intrinsic(String),
InvalidChar(u128),
- StackFrameLimitReached,
OutOfTls,
TlsOutOfBounds,
AbiViolation(String),
has: Align,
},
ValidationFailure(String),
- CalledClosureAsFunction,
VtableForArgumentlessMethod,
ModifiedConstantMemory,
ModifiedStatic,
AssumptionNotHeld,
- InlineAsm,
TypeNotPrimitive(Ty<'tcx>),
ReallocatedWrongMemoryKind(String, String),
DeallocatedWrongMemoryKind(String, String),
ReallocateNonBasePtr,
DeallocateNonBasePtr,
IncorrectAllocationInformation(Size, Size, Align, Align),
- Layout(layout::LayoutError<'tcx>),
HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(u64),
- Unreachable,
- Panic(PanicMessage<u64>),
ReadFromReturnPointer,
PathNotFound(Vec<String>),
- UnimplementedTraitSelection,
- /// Abort in case type errors are reached
- TypeckError,
- /// Resolution can fail if we are in a too generic context
- TooGeneric,
- /// Cannot compute this constant because it depends on another one
- /// which already produced an error
- ReferencedConstant,
- InfiniteLoop,
-}
-
-pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
-
-impl fmt::Display for InterpError<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // Forward `Display` to `Debug`
- write!(f, "{:?}", self)
- }
}
-impl fmt::Debug for InterpError<'_> {
+impl fmt::Debug for UnsupportedOpInfo<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use InterpError::*;
- match *self {
+ use UnsupportedOpInfo::*;
+ match self {
PointerOutOfBounds { ptr, msg, allocation_size } => {
write!(f, "{} failed: pointer must be in-bounds at offset {}, \
but is outside bounds of allocation {} which has size {}",
has.bytes(), required.bytes()),
TypeNotPrimitive(ty) =>
write!(f, "expected primitive type, got {}", ty),
- Layout(ref err) =>
- write!(f, "rustc layout computation failed: {:?}", err),
PathNotFound(ref path) =>
write!(f, "Cannot find path {:?}", path),
IncorrectAllocationInformation(size, size2, align, align2) =>
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
InvalidDiscriminant(val) =>
write!(f, "encountered invalid enum discriminant {}", val),
- Exit(code) =>
- write!(f, "exited with status code {}", code),
InvalidMemoryAccess =>
write!(f, "tried to access memory through an invalid pointer"),
DanglingPointerDeref =>
write!(f, "tried to dereference a function pointer"),
ExecuteMemory =>
write!(f, "tried to treat a memory pointer as a function pointer"),
- StackFrameLimitReached =>
- write!(f, "reached the configured maximum number of stack frames"),
OutOfTls =>
write!(f, "reached the maximum number of representable TLS keys"),
TlsOutOfBounds =>
existing object"),
HeapAllocZeroBytes =>
write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
- Unreachable =>
- write!(f, "entered unreachable code"),
ReadFromReturnPointer =>
write!(f, "tried to read from the return pointer"),
UnimplementedTraitSelection =>
write!(f, "there were unresolved type arguments during trait selection"),
- TypeckError =>
- write!(f, "encountered constants with type errors, stopping evaluation"),
- TooGeneric =>
- write!(f, "encountered overly generic constant"),
- ReferencedConstant =>
- write!(f, "referenced constant has errors"),
- InfiniteLoop =>
- write!(f, "duplicate interpreter state observed here, const evaluation will never \
- terminate"),
InvalidBoolOp(_) =>
write!(f, "invalid boolean operation"),
UnterminatedCString(_) =>
AbiViolation(ref msg) |
Intrinsic(ref msg) =>
write!(f, "{}", msg),
+ }
+ }
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum ResourceExhaustionInfo {
+ /// The stack grew too big.
+ StackFrameLimitReached,
+ /// The program ran into an infinite loop.
+ InfiniteLoop,
+}
+
+impl fmt::Debug for ResourceExhaustionInfo {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use ResourceExhaustionInfo::*;
+ match self {
+ StackFrameLimitReached =>
+ write!(f, "reached the configured maximum number of stack frames"),
+ InfiniteLoop =>
+ write!(f, "duplicate interpreter state observed here, const evaluation will never \
+ terminate"),
+ }
+ }
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum InterpError<'tcx> {
+ /// The program panicked.
+ Panic(PanicInfo<u64>),
+ /// The program caused undefined behavior.
+ UndefinedBehaviour(UndefinedBehaviourInfo),
+ /// The program did something the interpreter does not support (some of these *might* be UB
+ /// but the interpreter is not sure).
+ Unsupported(UnsupportedOpInfo<'tcx>),
+ /// The program was invalid (ill-typed, not sufficiently monomorphized, ...).
+ InvalidProgram(InvalidProgramInfo<'tcx>),
+ /// The program exhausted the interpreter's resources (stack/heap too big,
+ /// execution takes too long, ..).
+ ResourceExhaustion(ResourceExhaustionInfo),
+ /// Not actually an interpreter error -- used to signal that execution has exited
+ /// with the given status code. Used by Miri, but not by CTFE.
+ Exit(i32),
+}
+
+pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
+
+impl fmt::Display for InterpError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Forward `Display` to `Debug`
+ write!(f, "{:?}", self)
+ }
+}
+
+impl fmt::Debug for InterpError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use InterpError::*;
+ match *self {
+ Unsupported(ref msg) =>
+ write!(f, "{:?}", msg),
+ InvalidProgram(ref msg) =>
+ write!(f, "{:?}", msg),
+ UndefinedBehaviour(ref msg) =>
+ write!(f, "{:?}", msg),
+ ResourceExhaustion(ref msg) =>
+ write!(f, "{:?}", msg),
Panic(ref msg) =>
write!(f, "{:?}", msg),
+ Exit(code) =>
+ write!(f, "exited with status code {}", code),
}
}
}
//! An interpreter for MIR used in CTFE and by miri
#[macro_export]
-macro_rules! err {
- ($($tt:tt)*) => { Err($crate::mir::interpret::InterpError::$($tt)*.into()) };
+macro_rules! err_unsup {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::Unsupported(
+ $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
+ )
+ };
+}
+
+#[macro_export]
+macro_rules! err_inval {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::InvalidProgram(
+ $crate::mir::interpret::InvalidProgramInfo::$($tt)*
+ )
+ };
+}
+
+#[macro_export]
+macro_rules! err_ub {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::UndefinedBehaviour(
+ $crate::mir::interpret::UndefinedBehaviourInfo::$($tt)*
+ )
+ };
+}
+
+#[macro_export]
+macro_rules! err_panic {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::Panic(
+ $crate::mir::interpret::PanicInfo::$($tt)*
+ )
+ };
+}
+
+#[macro_export]
+macro_rules! err_exhaust {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::ResourceExhaustion(
+ $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
+ )
+ };
+}
+
+#[macro_export]
+macro_rules! throw_unsup {
+ ($($tt:tt)*) => { return Err(err_unsup!($($tt)*).into()) };
+}
+
+#[macro_export]
+macro_rules! throw_inval {
+ ($($tt:tt)*) => { return Err(err_inval!($($tt)*).into()) };
+}
+
+#[macro_export]
+macro_rules! throw_ub {
+ ($($tt:tt)*) => { return Err(err_ub!($($tt)*).into()) };
+}
+
+#[macro_export]
+macro_rules! throw_panic {
+ ($($tt:tt)*) => { return Err(err_panic!($($tt)*).into()) };
+}
+
+#[macro_export]
+macro_rules! throw_exhaust {
+ ($($tt:tt)*) => { return Err(err_exhaust!($($tt)*).into()) };
}
mod error;
pub use self::error::{
InterpErrorInfo, InterpResult, InterpError, AssertMessage, ConstEvalErr, struct_error,
- FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicMessage
+ FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicInfo, UnsupportedOpInfo,
+ InvalidProgramInfo, ResourceExhaustionInfo, UndefinedBehaviourInfo,
};
pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue};
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;
-use super::{
- AllocId, InterpResult, PanicMessage
-};
+use super::{AllocId, InterpResult};
/// Used by `check_in_alloc` to indicate context of check
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
#[inline]
fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_offset(val, i);
- if over { err!(Panic(PanicMessage::Overflow(mir::BinOp::Add))) } else { Ok(res) }
+ if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
}
#[inline]
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
- if over { err!(Panic(PanicMessage::Overflow(mir::BinOp::Add))) } else { Ok(res) }
+ if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
}
}
msg: CheckInAllocMsg,
) -> InterpResult<'tcx, ()> {
if self.offset > allocation_size {
- err!(PointerOutOfBounds {
- ptr: self.erase_tag(),
- msg,
- allocation_size,
- })
+ throw_unsup!(PointerOutOfBounds { ptr: self.erase_tag(), msg, allocation_size })
} else {
Ok(())
}
Scalar::check_data(data, size);
Ok(data)
}
- Scalar::Ptr(_) => err!(ReadPointerAsBytes),
+ Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes),
}
}
#[inline]
pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
match self {
- Scalar::Raw { data: 0, .. } => err!(InvalidNullPointerUsage),
- Scalar::Raw { .. } => err!(ReadBytesAsPointer),
+ Scalar::Raw { data: 0, .. } => throw_unsup!(InvalidNullPointerUsage),
+ Scalar::Raw { .. } => throw_unsup!(ReadBytesAsPointer),
Scalar::Ptr(p) => Ok(p),
}
}
match self {
Scalar::Raw { data: 0, size: 1 } => Ok(false),
Scalar::Raw { data: 1, size: 1 } => Ok(true),
- _ => err!(InvalidBool),
+ _ => throw_unsup!(InvalidBool),
}
}
let val = self.to_u32()?;
match ::std::char::from_u32(val) {
Some(c) => Ok(c),
- None => err!(InvalidChar(val as u128)),
+ None => throw_unsup!(InvalidChar(val as u128)),
}
}
pub fn not_undef(self) -> InterpResult<'static, Scalar<Tag>> {
match self {
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
- ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
+ ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::from_bytes(0))),
}
}
use crate::hir::def::{CtorKind, Namespace};
use crate::hir::def_id::DefId;
use crate::hir::{self, InlineAsm as HirInlineAsm};
-use crate::mir::interpret::{ConstValue, PanicMessage, Scalar};
+use crate::mir::interpret::{ConstValue, PanicInfo, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
}
}
Assert { ref cond, expected, ref msg, target, cleanup } => {
- use PanicMessage::*;
+ use PanicInfo::*;
let msg = match msg {
BoundsCheck { ref len, ref index } =>
BoundsCheck {
}
Assert { ref cond, ref msg, .. } => {
if cond.visit_with(visitor) {
- use PanicMessage::*;
+ use PanicInfo::*;
match msg {
BoundsCheck { ref len, ref index } =>
len.visit_with(visitor) || index.visit_with(visitor),
fn super_assert_message(&mut self,
msg: & $($mutability)? AssertMessage<'tcx>,
location: Location) {
- use crate::mir::interpret::PanicMessage::*;
+ use crate::mir::interpret::PanicInfo::*;
match msg {
BoundsCheck { len, index } => {
self.visit_operand(len, location);
/// ok on the premise that if `A: AutoTrait` held, but we indeed
/// encountered a problem (later on) with `A: AutoTrait. So we
/// currently set a flag on the stack node for `B: AutoTrait` (as
- /// well as the second instance of `A: AutoTrait`) to supress
+ /// well as the second instance of `A: AutoTrait`) to suppress
/// caching.
///
/// This is a simple, targeted fix. A more-performant fix requires
///
/// - is a defaulted trait,
/// - it also appears in the backtrace at some position `X`,
- /// - all the predicates at positions `X..` between `X` an the top are
+ /// - all the predicates at positions `X..` between `X` and the top are
/// also defaulted traits.
pub fn coinductive_match<I>(&mut self, cycle: I) -> bool
where
ty: a.ty,
}))
}
- (ConstValue::ByRef { .. }, _) => {
- bug!(
- "non-Scalar ConstValue encountered in super_relate_consts {:?} {:?}",
- a,
- b,
- );
- }
+
+ // FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment
+ // saying that we're not handling it intentionally.
+
+ // FIXME(const_generics): handle `ConstValue::ByRef` and `ConstValue::Slice`.
// FIXME(const_generics): this is wrong, as it is a projection
(ConstValue::Unevaluated(a_def_id, a_substs),
use rustc::ty::{self, Ty, TypeFoldable, Instance};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
-use rustc::mir::interpret::PanicMessage;
+use rustc::mir::interpret::PanicInfo;
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
use rustc_target::spec::abi::Abi;
use crate::base;
// checked operation, just a comparison with the minimum
// value, so we have to check for the assert message.
if !bx.check_overflow() {
- if let PanicMessage::OverflowNeg = *msg {
+ if let PanicInfo::OverflowNeg = *msg {
const_cond = Some(expected);
}
}
// Put together the arguments to the panic entry point.
let (lang_item, args) = match msg {
- PanicMessage::BoundsCheck { ref len, ref index } => {
+ PanicInfo::BoundsCheck { ref len, ref index } => {
let len = self.codegen_operand(&mut bx, len).immediate();
let index = self.codegen_operand(&mut bx, index).immediate();
cleanup: _,
} => {
self.consume_operand(loc, (cond, span), flow_state);
- use rustc::mir::interpret::PanicMessage;
- if let PanicMessage::BoundsCheck { ref len, ref index } = *msg {
+ use rustc::mir::interpret::PanicInfo;
+ if let PanicInfo::BoundsCheck { ref len, ref index } = *msg {
self.consume_operand(loc, (len, span), flow_state);
self.consume_operand(loc, (index, span), flow_state);
}
cleanup: _,
} => {
self.consume_operand(location, cond);
- use rustc::mir::interpret::PanicMessage;
- if let PanicMessage::BoundsCheck { ref len, ref index } = *msg {
+ use rustc::mir::interpret::PanicInfo;
+ if let PanicInfo::BoundsCheck { ref len, ref index } = *msg {
self.consume_operand(location, len);
self.consume_operand(location, index);
}
use rustc::infer::outlives::env::RegionBoundPairs;
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::mir::interpret::{ConstValue, PanicMessage};
+use rustc::mir::interpret::{ConstValue, PanicInfo};
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext};
use rustc::mir::*;
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
- if let PanicMessage::BoundsCheck { ref len, ref index } = *msg {
+ if let PanicInfo::BoundsCheck { ref len, ref index } = *msg {
if len.ty(body, tcx) != tcx.types.usize {
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
}
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
-use rustc::mir::interpret::{PanicMessage::BoundsCheck};
+use rustc::mir::interpret::{PanicInfo::BoundsCheck};
use rustc::mir::*;
use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
use rustc::middle::region;
-use rustc::mir::interpret::PanicMessage;
+use rustc::mir::interpret::PanicInfo;
use rustc::mir::*;
use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
use syntax_pos::Span;
block,
Operand::Move(is_min),
false,
- PanicMessage::OverflowNeg,
+ PanicInfo::OverflowNeg,
expr_span,
);
}
let val = result_value.clone().field(val_fld, ty);
let of = result_value.field(of_fld, bool_ty);
- let err = PanicMessage::Overflow(op);
+ let err = PanicInfo::Overflow(op);
block = self.assert(block, Operand::Move(of), false, err, span);
// and 2. there are two possible failure cases, divide-by-zero and overflow.
let zero_err = if op == BinOp::Div {
- PanicMessage::DivisionByZero
+ PanicInfo::DivisionByZero
} else {
- PanicMessage::RemainderByZero
+ PanicInfo::RemainderByZero
};
- let overflow_err = PanicMessage::Overflow(op);
+ let overflow_err = PanicInfo::Overflow(op);
// Check for / 0
let is_zero = self.temp(bool_ty, span);
use crate::interpret::{self,
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar,
RawConst, ConstValue,
- InterpResult, InterpErrorInfo, InterpError, GlobalId, InterpCx, StackPopCleanup,
+ InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
Allocation, AllocId, MemoryKind,
snapshot, RefTracking, intern_const_alloc_recursive,
};
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalError {
fn into(self) -> InterpErrorInfo<'tcx> {
- InterpError::MachineError(self.to_string()).into()
+ err_unsup!(MachineError(self.to_string())).into()
}
}
ecx.goto_block(ret)?; // fully evaluated and done
Ok(None)
} else {
- err!(MachineError(format!("calling non-const function `{}`", instance)))
+ throw_unsup!(MachineError(format!("calling non-const function `{}`", instance)))
};
}
}
Ok(Some(match ecx.load_mir(instance.def) {
Ok(body) => body,
Err(err) => {
- if let InterpError::NoMirFor(ref path) = err.kind {
+ if let err_unsup!(NoMirFor(ref path)) = err.kind {
return Err(
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
.into(),
_tcx: TyCtxt<'tcx>,
_def_id: DefId,
) -> InterpResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
- err!(ReadForeignStatic)
+ throw_unsup!(ReadForeignStatic)
}
#[inline(always)]
// any other kind of error will be reported to the user as a deny-by-default lint
_ => if let Some(p) = cid.promoted {
let span = tcx.promoted_mir(def_id)[p].span;
- if let InterpError::ReferencedConstant = err.error {
+ if let err_inval!(ReferencedConstant) = err.error {
err.report_as_error(
tcx.at(span),
"evaluation of constant expression failed",
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
- Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
+ Scalar, InterpResult, Pointer, PointerArithmetic,
};
use rustc::mir::CastKind;
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
bug!("reifying a fn ptr that requires const arguments");
}
- let instance: InterpResult<'tcx, _> = ty::Instance::resolve(
+ let instance = ty::Instance::resolve(
*self.tcx,
self.param_env,
def_id,
substs,
- ).ok_or_else(|| InterpError::TooGeneric.into());
- let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance?));
+ ).ok_or_else(|| err_inval!(TooGeneric))?;
+ let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
}
_ => bug!("reify fn pointer on {:?}", src.layout.ty),
},
// Casts to bool are not permitted by rustc, no need to handle them here.
- _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
+ _ => throw_unsup!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
}
}
use rustc::mir::interpret::{
ErrorHandled,
GlobalId, Scalar, Pointer, FrameInfo, AllocId,
- InterpResult, InterpError,
- truncate, sign_extend,
+ InterpResult, truncate, sign_extend,
};
use rustc_data_structures::fx::FxHashMap;
impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
match self.value {
- LocalValue::Dead => err!(DeadLocal),
+ LocalValue::Dead => throw_unsup!(DeadLocal),
LocalValue::Uninitialized =>
bug!("The type checker should prevent reading from a never-written local"),
LocalValue::Live(val) => Ok(val),
&mut self,
) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
match self.value {
- LocalValue::Dead => err!(DeadLocal),
+ LocalValue::Dead => throw_unsup!(DeadLocal),
LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
ref mut local @ LocalValue::Live(Operand::Immediate(_)) |
ref mut local @ LocalValue::Uninitialized => {
#[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
- self.tcx.layout_of(self.param_env.and(ty))
- .map_err(|layout| InterpError::Layout(layout).into())
+ self.tcx
+ .layout_of(self.param_env.and(ty))
+ .map_err(|layout| err_inval!(Layout(layout)).into())
}
}
&substs,
)),
None => if substs.needs_subst() {
- err!(TooGeneric).into()
+ throw_inval!(TooGeneric)
} else {
Ok(substs)
},
self.param_env,
def_id,
substs,
- ).ok_or_else(|| InterpError::TooGeneric.into())
+ ).ok_or_else(|| err_inval!(TooGeneric).into())
}
pub fn load_mir(
&& self.tcx.has_typeck_tables(did)
&& self.tcx.typeck_tables_of(did).tainted_by_errors
{
- return err!(TypeckError);
+ throw_inval!(TypeckError)
}
trace!("load mir {:?}", instance);
match instance {
ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) {
Ok(self.tcx.optimized_mir(did))
} else {
- err!(NoMirFor(self.tcx.def_path_str(def_id)))
+ throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id)))
},
_ => Ok(self.tcx.instance_mir(instance)),
}
match self.stack.last() {
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?),
None => if t.needs_subst() {
- err!(TooGeneric).into()
+ throw_inval!(TooGeneric)
} else {
Ok(t)
},
let substituted = t.subst(*self.tcx, substs);
if substituted.needs_subst() {
- return err!(TooGeneric);
+ throw_inval!(TooGeneric)
}
Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted))
info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance);
if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit {
- err!(StackFrameLimitReached)
+ throw_exhaust!(StackFrameLimitReached)
} else {
Ok(())
}
}
} else {
// Uh, that shouldn't happen... the function did not intend to return
- return err!(Unreachable);
+ throw_ub!(Unreachable)
}
// Jump to new block -- *after* validation so that the spans make more sense.
match frame.return_to_block {
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
match err {
- ErrorHandled::Reported => InterpError::ReferencedConstant,
- ErrorHandled::TooGeneric => InterpError::TooGeneric,
+ ErrorHandled::Reported =>
+ err_inval!(ReferencedConstant),
+ ErrorHandled::TooGeneric =>
+ err_inval!(TooGeneric),
}
})?;
self.raw_const_to_mplace(val)
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
-use rustc::mir::interpret::{
- InterpResult, ErrorHandled,
-};
+use rustc::mir::interpret::{InterpResult, ErrorHandled};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use syntax_pos::Span;
use super::{
- ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
+ ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
if let Err(error) = interned {
// This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
// to read enum discriminants in order to find references in enum variant fields.
- if let InterpError::ValidationFailure(_) = error.kind {
+ if let err_unsup!(ValidationFailure(_)) = error.kind {
let err = crate::const_eval::error_to_const_error(&ecx, error);
match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
Ok(mut diag) => {
}
} else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
// dangling pointer
- return err!(ValidationFailure(
- "encountered dangling pointer in final constant".into(),
- ))
+ throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into()))
}
}
Ok(())
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
-use rustc::mir::interpret::{
- InterpResult, InterpError, Scalar, PanicMessage,
-};
+use rustc::mir::interpret::{InterpResult, Scalar};
use super::{
Machine, PlaceTy, OpTy, InterpCx, Immediate,
let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
let kind = match layout_of.abi {
ty::layout::Abi::Scalar(ref scalar) => scalar.value,
- _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
+ _ => Err(err_unsup!(TypeNotPrimitive(ty)))?,
};
let out_val = if intrinsic_name.ends_with("_nonzero") {
if bits == 0 {
- return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
+ throw_unsup!(Intrinsic(format!("{} called on 0", intrinsic_name)))
}
numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
} else {
if overflowed {
let layout = self.layout_of(substs.type_at(0))?;
let r_val = r.to_scalar()?.to_bits(layout.size)?;
- return err!(Intrinsic(
- format!("Overflowing shift by {} in {}", r_val, intrinsic_name),
- ));
+ throw_unsup!(
+ Intrinsic(format!("Overflowing shift by {} in {}", r_val, intrinsic_name))
+ )
}
self.write_scalar(val, dest)?;
}
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
- return Err(InterpError::Panic(PanicMessage::Panic { msg, file, line, col }).into());
+ throw_panic!(Panic { msg, file, line, col })
} else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
assert!(args.len() == 2);
// &'static str, &(&'static str, u32, u32)
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
- return Err(InterpError::Panic(PanicMessage::Panic { msg, file, line, col }).into());
+ throw_panic!(Panic { msg, file, line, col })
} else {
return Ok(false);
}
use rustc::ty::{self, TyCtxt};
use super::{
- Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra,
+ Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
};
int: u64,
) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
Err((if int == 0 {
- InterpError::InvalidNullPointerUsage
+ err_unsup!(InvalidNullPointerUsage)
} else {
- InterpError::ReadBytesAsPointer
+ err_unsup!(ReadBytesAsPointer)
}).into())
}
_mem: &Memory<'mir, 'tcx, Self>,
_ptr: Pointer<Self::PointerTag>,
) -> InterpResult<'tcx, u64> {
- err!(ReadPointerAsBytes)
+ throw_unsup!(ReadPointerAsBytes)
}
}
use super::{
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
- InterpResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic,
+ InterpResult, Scalar, GlobalAlloc, PointerArithmetic,
Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg,
};
match self {
FnVal::Instance(instance) =>
Ok(instance),
- FnVal::Other(_) =>
- err!(MachineError(
- format!("Expected instance function pointer, got 'other' pointer")
- )),
+ FnVal::Other(_) => throw_unsup!(MachineError(format!(
+ "Expected instance function pointer, got 'other' pointer"
+ ))),
}
}
}
kind: MemoryKind<M::MemoryKinds>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
if ptr.offset.bytes() != 0 {
- return err!(ReallocateNonBasePtr);
+ throw_unsup!(ReallocateNonBasePtr)
}
// For simplicities' sake, we implement reallocate as "alloc, copy, dealloc".
trace!("deallocating: {}", ptr.alloc_id);
if ptr.offset.bytes() != 0 {
- return err!(DeallocateNonBasePtr);
+ throw_unsup!(DeallocateNonBasePtr)
}
let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
Some(alloc) => alloc,
None => {
// Deallocating static memory -- always an error
- return match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
- Some(GlobalAlloc::Function(..)) => err!(DeallocatedWrongMemoryKind(
+ return Err(match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
+ Some(GlobalAlloc::Function(..)) => err_unsup!(DeallocatedWrongMemoryKind(
"function".to_string(),
format!("{:?}", kind),
)),
- Some(GlobalAlloc::Static(..)) |
- Some(GlobalAlloc::Memory(..)) => err!(DeallocatedWrongMemoryKind(
- "static".to_string(),
- format!("{:?}", kind),
- )),
- None => err!(DoubleFree)
+ Some(GlobalAlloc::Static(..)) | Some(GlobalAlloc::Memory(..)) => err_unsup!(
+ DeallocatedWrongMemoryKind("static".to_string(), format!("{:?}", kind))
+ ),
+ None => err_unsup!(DoubleFree),
}
+ .into());
}
};
if alloc_kind != kind {
- return err!(DeallocatedWrongMemoryKind(
+ throw_unsup!(DeallocatedWrongMemoryKind(
format!("{:?}", alloc_kind),
format!("{:?}", kind),
- ));
+ ))
}
if let Some((size, align)) = old_size_and_align {
if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align {
let bytes = Size::from_bytes(alloc.bytes.len() as u64);
- return err!(IncorrectAllocationInformation(size,
- bytes,
- align,
- alloc.align));
+ throw_unsup!(IncorrectAllocationInformation(size, bytes, align, alloc.align))
}
}
} else {
// The biggest power of two through which `offset` is divisible.
let offset_pow2 = 1 << offset.trailing_zeros();
- err!(AlignmentCheckFailed {
+ throw_unsup!(AlignmentCheckFailed {
has: Align::from_bytes(offset_pow2).unwrap(),
required: align,
})
assert!(size.bytes() == 0);
// Must be non-NULL and aligned.
if bits == 0 {
- return err!(InvalidNullPointerUsage);
+ throw_unsup!(InvalidNullPointerUsage)
}
check_offset_align(bits, align)?;
None
// got picked we might be aligned even if this check fails.
// We instead have to fall back to converting to an integer and checking
// the "real" alignment.
- return err!(AlignmentCheckFailed {
+ throw_unsup!(AlignmentCheckFailed {
has: alloc_align,
required: align,
- });
+ })
}
check_offset_align(ptr.offset.bytes(), align)?;
Some(GlobalAlloc::Memory(mem)) =>
Cow::Borrowed(mem),
Some(GlobalAlloc::Function(..)) =>
- return err!(DerefFunctionPointer),
+ throw_unsup!(DerefFunctionPointer),
None =>
- return err!(DanglingPointerDeref),
+ throw_unsup!(DanglingPointerDeref),
Some(GlobalAlloc::Static(def_id)) => {
// We got a "lazy" static that has not been computed yet.
if tcx.is_foreign_item(def_id) {
// for statics
assert!(tcx.is_static(def_id));
match err {
- ErrorHandled::Reported => InterpError::ReferencedConstant,
- ErrorHandled::TooGeneric => InterpError::TooGeneric,
+ ErrorHandled::Reported =>
+ err_inval!(ReferencedConstant),
+ ErrorHandled::TooGeneric =>
+ err_inval!(TooGeneric),
}
})?;
// Make sure we use the ID of the resolved memory, not the lazy one!
// to give us a cheap reference.
let alloc = Self::get_static_alloc(memory_extra, tcx, id)?;
if alloc.mutability == Mutability::Immutable {
- return err!(ModifiedConstantMemory);
+ throw_unsup!(ModifiedConstantMemory)
}
match M::STATIC_KIND {
Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())),
- None => err!(ModifiedStatic),
+ None => throw_unsup!(ModifiedStatic),
}
});
// Unpack the error type manually because type inference doesn't
Ok(a) => {
let a = &mut a.1;
if a.mutability == Mutability::Immutable {
- return err!(ModifiedConstantMemory);
+ throw_unsup!(ModifiedConstantMemory)
}
Ok(a)
}
if let Ok(_) = self.get_fn_alloc(id) {
return if let AllocCheck::Dereferencable = liveness {
// The caller requested no function pointers.
- err!(DerefFunctionPointer)
+ throw_unsup!(DerefFunctionPointer)
} else {
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
};
.expect("deallocated pointers should all be recorded in \
`dead_alloc_map`"))
} else {
- err!(DanglingPointerDeref)
+ throw_unsup!(DanglingPointerDeref)
},
}
}
} else {
match self.tcx.alloc_map.lock().get(id) {
Some(GlobalAlloc::Function(instance)) => Ok(FnVal::Instance(instance)),
- _ => Err(InterpError::ExecuteMemory.into()),
+ _ => throw_unsup!(ExecuteMemory),
}
}
}
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
let ptr = self.force_ptr(ptr)?; // We definitely need a pointer value.
if ptr.offset.bytes() != 0 {
- return err!(InvalidFunctionPointer);
+ throw_unsup!(InvalidFunctionPointer)
}
self.get_fn_alloc(ptr.alloc_id)
}
if (src.offset <= dest.offset && src.offset + size > dest.offset) ||
(dest.offset <= src.offset && dest.offset + size > src.offset)
{
- return err!(Intrinsic(
+ throw_unsup!(Intrinsic(
"copy_nonoverlapping called on overlapping ranges".to_string(),
- ));
+ ))
}
}
use rustc::mir::interpret::{
GlobalId, AllocId,
ConstValue, Pointer, Scalar,
- InterpResult, InterpError,
- sign_extend, truncate,
+ InterpResult, sign_extend, truncate,
};
use super::{
InterpCx, Machine,
) -> InterpResult<'tcx, &str> {
let len = mplace.len(self)?;
let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
- let str = ::std::str::from_utf8(bytes)
- .map_err(|err| InterpError::ValidationFailure(err.to_string()))?;
+ let str = ::std::str::from_utf8(bytes).map_err(|err| {
+ err_unsup!(ValidationFailure(err.to_string()))
+ })?;
Ok(str)
}
mir_place.iterate(|place_base, place_projection| {
let mut op = match place_base {
- PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
+ PlaceBase::Local(mir::RETURN_PLACE) =>
+ throw_unsup!(ReadFromReturnPointer),
PlaceBase::Local(local) => {
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
};
// Early-return cases.
match val.val {
- ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize
+ ConstValue::Param(_) =>
+ // FIXME(oli-obk): try to monomorphize
+ throw_inval!(TooGeneric),
ConstValue::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
return Ok(OpTy::from(self.const_eval_raw(GlobalId {
layout::DiscriminantKind::Tag => {
let bits_discr = match raw_discr.to_bits(discr_val.layout.size) {
Ok(raw_discr) => raw_discr,
- Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())),
+ Err(_) =>
+ throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag())),
};
let real_discr = if discr_val.layout.ty.is_signed() {
// going from layout tag type to typeck discriminant type
.discriminants(*def_id, self.tcx.tcx)
.find(|(_, var)| var.val == real_discr),
_ => bug!("tagged layout for non-adt non-generator"),
- }.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?;
+ }.ok_or_else(
+ || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag()))
+ )?;
(real_discr, index.0)
},
layout::DiscriminantKind::Niche {
} => {
let variants_start = niche_variants.start().as_u32() as u128;
let variants_end = niche_variants.end().as_u32() as u128;
- let raw_discr = raw_discr.not_undef()
- .map_err(|_| InterpError::InvalidDiscriminant(ScalarMaybeUndef::Undef))?;
+ let raw_discr = raw_discr.not_undef().map_err(|_| {
+ err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef))
+ })?;
match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
Err(ptr) => {
// The niche must be just 0 (which an inbounds pointer value never is)
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
!self.memory.ptr_may_be_null(ptr);
if !ptr_valid {
- return err!(InvalidDiscriminant(raw_discr.erase_tag().into()));
+ throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag().into()))
}
(dataful_variant.as_u32() as u128, dataful_variant)
},
use rustc::ty::{self, layout::TyLayout};
use syntax::ast::FloatTy;
use rustc_apfloat::Float;
-use rustc::mir::interpret::{InterpResult, PanicMessage, Scalar};
+use rustc::mir::interpret::{InterpResult, Scalar};
use super::{InterpCx, PlaceTy, Immediate, Machine, ImmTy};
r,
right_layout.ty
);
- return err!(Unimplemented(msg));
+ throw_unsup!(Unimplemented(msg))
}
// Operations that need special treatment for signed integers
return Ok((Scalar::from_bool(op(&l, &r)), false));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
- Div if r == 0 => return err!(Panic(PanicMessage::DivisionByZero)),
- Rem if r == 0 => return err!(Panic(PanicMessage::RemainderByZero)),
+ Div if r == 0 => throw_panic!(DivisionByZero),
+ Rem if r == 0 => throw_panic!(RemainderByZero),
Div => Some(i128::overflowing_div),
Rem => Some(i128::overflowing_rem),
Add => Some(i128::overflowing_add),
Add => u128::overflowing_add,
Sub => u128::overflowing_sub,
Mul => u128::overflowing_mul,
- Div if r == 0 => return err!(Panic(PanicMessage::DivisionByZero)),
- Rem if r == 0 => return err!(Panic(PanicMessage::RemainderByZero)),
+ Div if r == 0 => throw_panic!(DivisionByZero),
+ Rem if r == 0 => throw_panic!(RemainderByZero),
Div => u128::overflowing_div,
Rem => u128::overflowing_rem,
_ => bug!(),
r,
right_layout.ty,
);
- return err!(Unimplemented(msg));
+ throw_unsup!(Unimplemented(msg))
}
};
use super::{
GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic,
- InterpCx, Machine, AllocMap, AllocationExtra, PanicMessage,
- RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue
+ InterpCx, Machine, AllocMap, AllocationExtra,
+ RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue,
};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
// This can be violated because this runs during promotion on code where the
// type system has not yet ensured that such things don't happen.
debug!("tried to access element {} of array/slice with length {}", field, len);
- return err!(Panic(PanicMessage::BoundsCheck { len, index: field }));
+ throw_panic!(BoundsCheck { len, index: field });
}
stride * field
}
.layout_of(self.monomorphize(self.frame().body.return_ty())?)?,
}
}
- None => return err!(InvalidNullPointerUsage),
+ None => throw_unsup!(InvalidNullPointerUsage),
},
PlaceBase::Local(local) => PlaceTy {
// This works even for dead/uninitialized locals; we check further when writing
use rustc::mir;
use rustc::mir::interpret::{
AllocId, Pointer, Scalar,
- Relocations, Allocation, UndefMask,
- InterpResult, InterpError,
+ Relocations, Allocation, UndefMask, InterpResult,
};
use rustc::ty::{self, TyCtxt};
}
// Second cycle
- Err(InterpError::InfiniteLoop.into())
+ throw_exhaust!(InfiniteLoop)
}
}
// size of MIR constantly.
Nop => {}
- InlineAsm { .. } => return err!(InlineAsm),
+ InlineAsm { .. } => throw_unsup!(InlineAsm),
}
self.stack[frame_idx].stmt += 1;
use rustc_target::spec::abi::Abi;
use super::{
- InterpResult, PointerArithmetic, InterpError, Scalar,
+ InterpResult, PointerArithmetic, Scalar,
InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
};
self.frame_mut().stmt = 0;
Ok(())
} else {
- err!(Unreachable)
+ throw_ub!(Unreachable)
}
}
},
_ => {
let msg = format!("can't handle callee of type {:?}", func.layout.ty);
- return err!(Unimplemented(msg));
+ throw_unsup!(Unimplemented(msg))
}
};
let args = self.eval_operands(args)?;
self.goto_block(Some(target))?;
} else {
// Compute error message
- use rustc::mir::interpret::PanicMessage::*;
- return match msg {
+ use rustc::mir::interpret::PanicInfo::*;
+ return Err(match msg {
BoundsCheck { ref len, ref index } => {
- let len = self.read_immediate(self.eval_operand(len, None)?)
- .expect("can't eval len").to_scalar()?
+ let len = self
+ .read_immediate(self.eval_operand(len, None)?)
+ .expect("can't eval len")
+ .to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
- let index = self.read_immediate(self.eval_operand(index, None)?)
- .expect("can't eval index").to_scalar()?
+ let index = self
+ .read_immediate(self.eval_operand(index, None)?)
+ .expect("can't eval index")
+ .to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
- err!(Panic(BoundsCheck { len, index }))
+ err_panic!(BoundsCheck { len, index })
}
- Overflow(op) =>
- err!(Panic(Overflow(*op))),
- OverflowNeg =>
- err!(Panic(OverflowNeg)),
- DivisionByZero =>
- err!(Panic(DivisionByZero)),
- RemainderByZero =>
- err!(Panic(RemainderByZero)),
- GeneratorResumedAfterReturn =>
- err!(Panic(GeneratorResumedAfterReturn)),
- GeneratorResumedAfterPanic =>
- err!(Panic(GeneratorResumedAfterPanic)),
- Panic { .. } =>
- bug!("`Panic` variant cannot occur in MIR"),
- };
+ Overflow(op) => err_panic!(Overflow(*op)),
+ OverflowNeg => err_panic!(OverflowNeg),
+ DivisionByZero => err_panic!(DivisionByZero),
+ RemainderByZero => err_panic!(RemainderByZero),
+ GeneratorResumedAfterReturn => err_panic!(GeneratorResumedAfterReturn),
+ GeneratorResumedAfterPanic => err_panic!(GeneratorResumedAfterPanic),
+ Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
+ }
+ .into());
}
}
`simplify_branches` mir pass"),
FalseUnwind { .. } => bug!("should have been eliminated by\
`simplify_branches` mir pass"),
- Unreachable => return err!(Unreachable),
+ Unreachable => throw_ub!(Unreachable),
}
Ok(())
return Ok(());
}
let caller_arg = caller_arg.next()
- .ok_or_else(|| InterpError::FunctionArgCountMismatch)?;
+ .ok_or_else(|| err_unsup!(FunctionArgCountMismatch)) ?;
if rust_abi {
debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
}
// Now, check
if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) {
- return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
+ throw_unsup!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty))
}
// We allow some transmutes here
self.copy_op_transmute(caller_arg, callee_arg)
match instance.def {
ty::InstanceDef::Intrinsic(..) => {
if caller_abi != Abi::RustIntrinsic {
- return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic));
+ throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))
}
// The intrinsic itself cannot diverge, so if we got here without a return
// place... (can happen e.g., for transmute returning `!`)
let dest = match dest {
Some(dest) => dest,
- None => return err!(Unreachable)
+ None => throw_ub!(Unreachable)
};
M::call_intrinsic(self, instance, args, dest)?;
// No stack frame gets pushed, the main loop will just act as if the
abi,
};
if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
- return err!(FunctionAbiMismatch(caller_abi, callee_abi));
+ throw_unsup!(FunctionAbiMismatch(caller_abi, callee_abi))
}
}
// Now we should have no more caller args
if caller_iter.next().is_some() {
trace!("Caller has passed too many args");
- return err!(FunctionArgCountMismatch);
+ throw_unsup!(FunctionArgCountMismatch)
}
// Don't forget to check the return type!
if let Some(caller_ret) = dest {
caller_ret.layout,
callee_ret.layout,
) {
- return err!(FunctionRetMismatch(
- caller_ret.layout.ty, callee_ret.layout.ty
- ));
+ throw_unsup!(
+ FunctionRetMismatch(caller_ret.layout.ty, callee_ret.layout.ty)
+ )
}
} else {
let local = mir::RETURN_PLACE;
let ty = self.frame().body.local_decls[local].ty;
if !self.tcx.is_ty_uninhabited_from_any_module(ty) {
- return err!(FunctionRetMismatch(self.tcx.types.never, ty));
+ throw_unsup!(FunctionRetMismatch(self.tcx.types.never, ty))
}
}
Ok(())
use rustc::ty::{self, Ty, Instance};
use rustc::ty::layout::{Size, Align, LayoutOf};
-use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic};
+use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
-use super::{InterpCx, InterpError, Machine, MemoryKind, FnVal};
+use super::{InterpCx, Machine, MemoryKind, FnVal};
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
self.param_env,
def_id,
substs,
- ).ok_or_else(|| InterpError::TooGeneric)?;
+ ).ok_or_else(|| err_inval!(TooGeneric))?;
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?;
self.memory
use std::hash::Hash;
use super::{
- GlobalAlloc, InterpResult, InterpError,
+ GlobalAlloc, InterpResult,
OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
};
-macro_rules! validation_failure {
+macro_rules! throw_validation_failure {
($what:expr, $where:expr, $details:expr) => {{
let where_ = path_format(&$where);
let where_ = if where_.is_empty() {
} else {
format!(" at {}", where_)
};
- err!(ValidationFailure(format!(
+ throw_unsup!(ValidationFailure(format!(
"encountered {}{}, but expected {}",
$what, where_, $details,
)))
} else {
format!(" at {}", where_)
};
- err!(ValidationFailure(format!(
+ throw_unsup!(ValidationFailure(format!(
"encountered {}{}",
$what, where_,
)))
($e:expr, $what:expr, $where:expr, $details:expr) => {{
match $e {
Ok(x) => x,
- Err(_) => return validation_failure!($what, $where, $details),
+ Err(_) => throw_validation_failure!($what, $where, $details),
}
}};
($e:expr, $what:expr, $where:expr) => {{
match $e {
Ok(x) => x,
- Err(_) => return validation_failure!($what, $where),
+ Err(_) => throw_validation_failure!($what, $where),
}
}}
}
match self.walk_value(op) {
Ok(()) => Ok(()),
Err(err) => match err.kind {
- InterpError::InvalidDiscriminant(val) =>
- validation_failure!(
+ err_unsup!(InvalidDiscriminant(val)) =>
+ throw_validation_failure!(
val, self.path, "a valid enum discriminant"
),
- InterpError::ReadPointerAsBytes =>
- validation_failure!(
+ err_unsup!(ReadPointerAsBytes) =>
+ throw_validation_failure!(
"a pointer", self.path, "plain (non-pointer) bytes"
),
_ => Err(err),
ptr, size, align
);
match err.kind {
- InterpError::InvalidNullPointerUsage =>
- return validation_failure!("NULL reference", self.path),
- InterpError::AlignmentCheckFailed { required, has } =>
- return validation_failure!(format!("unaligned reference \
+ err_unsup!(InvalidNullPointerUsage) =>
+ throw_validation_failure!("NULL reference", self.path),
+ err_unsup!(AlignmentCheckFailed { required, has }) =>
+ throw_validation_failure!(format!("unaligned reference \
(required {} byte alignment but found {})",
required.bytes(), has.bytes()), self.path),
- InterpError::ReadBytesAsPointer =>
- return validation_failure!(
+ err_unsup!(ReadBytesAsPointer) =>
+ throw_validation_failure!(
"dangling reference (created from integer)",
self.path
),
_ =>
- return validation_failure!(
+ throw_validation_failure!(
"dangling reference (not entirely in bounds)",
self.path
),
fn visit_uninhabited(&mut self) -> InterpResult<'tcx>
{
- validation_failure!("a value of an uninhabited type", self.path)
+ throw_validation_failure!("a value of an uninhabited type", self.path)
}
fn visit_scalar(
if lo == 1 && hi == max_hi {
// Only NULL is the niche. So make sure the ptr is NOT NULL.
if self.ecx.memory.ptr_may_be_null(ptr) {
- return validation_failure!(
+ throw_validation_failure!(
"a potentially NULL pointer",
self.path,
format!(
"something that cannot possibly fail to be {}",
wrapping_range_format(&layout.valid_range, max_hi)
)
- );
+ )
}
return Ok(());
} else {
// Conservatively, we reject, because the pointer *could* have a bad
// value.
- return validation_failure!(
+ throw_validation_failure!(
"a pointer",
self.path,
format!(
"something that cannot possibly fail to be {}",
wrapping_range_format(&layout.valid_range, max_hi)
)
- );
+ )
}
}
Ok(data) =>
if wrapping_range_contains(&layout.valid_range, bits) {
Ok(())
} else {
- validation_failure!(
+ throw_validation_failure!(
bits,
self.path,
format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
Err(err) => {
// For some errors we might be able to provide extra information
match err.kind {
- InterpError::ReadUndefBytes(offset) => {
+ err_unsup!(ReadUndefBytes(offset)) => {
// Some byte was undefined, determine which
// element that byte belongs to so we can
// provide an index.
let i = (offset.bytes() / ty_size.bytes()) as usize;
self.path.push(PathElem::ArrayElem(i));
- return validation_failure!(
- "undefined bytes", self.path
- )
+ throw_validation_failure!("undefined bytes", self.path)
},
// Other errors shouldn't be possible
_ => return Err(err),
use rustc::mir::visit::{
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
};
-use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, InterpError, PanicMessage};
+use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, PanicInfo};
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::subst::InternalSubsts;
let diagnostic = error_to_const_error(&self.ecx, error);
use rustc::mir::interpret::InterpError::*;
match diagnostic.error {
- // don't report these, they make no sense in a const prop context
- | MachineError(_)
- | Exit(_)
- // at runtime these transformations might make sense
- // FIXME: figure out the rules and start linting
- | FunctionAbiMismatch(..)
- | FunctionArgMismatch(..)
- | FunctionRetMismatch(..)
- | FunctionArgCountMismatch
- // fine at runtime, might be a register address or sth
- | ReadBytesAsPointer
- // fine at runtime
- | ReadForeignStatic
- | Unimplemented(_)
- // don't report const evaluator limits
- | StackFrameLimitReached
- | NoMirFor(..)
- | InlineAsm
- => {},
-
- | InvalidMemoryAccess
- | DanglingPointerDeref
- | DoubleFree
- | InvalidFunctionPointer
- | InvalidBool
- | InvalidDiscriminant(..)
- | PointerOutOfBounds { .. }
- | InvalidNullPointerUsage
- | ValidationFailure(..)
- | InvalidPointerMath
- | ReadUndefBytes(_)
- | DeadLocal
- | InvalidBoolOp(_)
- | DerefFunctionPointer
- | ExecuteMemory
- | Intrinsic(..)
- | InvalidChar(..)
- | AbiViolation(_)
- | AlignmentCheckFailed{..}
- | CalledClosureAsFunction
- | VtableForArgumentlessMethod
- | ModifiedConstantMemory
- | ModifiedStatic
- | AssumptionNotHeld
- // FIXME: should probably be removed and turned into a bug! call
- | TypeNotPrimitive(_)
- | ReallocatedWrongMemoryKind(_, _)
- | DeallocatedWrongMemoryKind(_, _)
- | ReallocateNonBasePtr
- | DeallocateNonBasePtr
- | IncorrectAllocationInformation(..)
- | UnterminatedCString(_)
- | HeapAllocZeroBytes
- | HeapAllocNonPowerOfTwoAlignment(_)
- | Unreachable
- | ReadFromReturnPointer
- | ReferencedConstant
- | InfiniteLoop
- => {
- // FIXME: report UB here
- },
-
- | OutOfTls
- | TlsOutOfBounds
- | PathNotFound(_)
- => bug!("these should not be in rustc, but in miri's machine errors"),
-
- | Layout(_)
- | UnimplementedTraitSelection
- | TypeckError
- | TooGeneric
- // these are just noise
- => {},
-
- // non deterministic
- | ReadPointerAsBytes
- // FIXME: implement
- => {},
-
- | Panic(_)
- => {
+ Exit(_) => bug!("the CTFE program cannot exit"),
+ Unsupported(_)
+ | UndefinedBehaviour(_)
+ | InvalidProgram(_)
+ | ResourceExhaustion(_) => {
+ // Ignore these errors.
+ }
+ Panic(_) => {
diagnostic.report_as_lint(
self.ecx.tcx,
"this expression will panic at runtime",
// Need to do overflow check here: For actual CTFE, MIR
// generation emits code that does this before calling the op.
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
- return err!(Panic(PanicMessage::OverflowNeg));
+ throw_panic!(OverflowNeg)
}
}
UnOp::Not => {
)
} else {
if overflow {
- let err = InterpError::Panic(PanicMessage::Overflow(op)).into();
+ let err = err_panic!(Overflow(op)).into();
let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
return None;
}
.as_local_hir_id(self.source.def_id())
.expect("some part of a failing const eval must be local");
let msg = match msg {
- PanicMessage::Overflow(_) |
- PanicMessage::OverflowNeg |
- PanicMessage::DivisionByZero |
- PanicMessage::RemainderByZero =>
+ PanicInfo::Overflow(_) |
+ PanicInfo::OverflowNeg |
+ PanicInfo::DivisionByZero |
+ PanicInfo::RemainderByZero =>
msg.description().to_owned(),
- PanicMessage::BoundsCheck { ref len, ref index } => {
+ PanicInfo::BoundsCheck { ref len, ref index } => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
let mut cases = create_cases(body, &transform, |point| Some(point.resume));
- use rustc::mir::interpret::PanicMessage::{
+ use rustc::mir::interpret::PanicInfo::{
GeneratorResumedAfterPanic,
GeneratorResumedAfterReturn,
};
///
/// ```no_run
/// # #![allow(unused_must_use)]
- /// use std::ffi::{CString};
+ /// use std::ffi::CString;
///
/// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
/// unsafe {
///
/// ```no_run
/// # #![allow(unused_must_use)]
- /// use std::ffi::{CString};
+ /// use std::ffi::CString;
///
/// let hello = CString::new("Hello").expect("CString::new failed");
/// let ptr = hello.as_ptr();
quoted::TokenTree::Sequence(
DelimSpan::dummy(),
Lrc::new(quoted::SequenceRepetition {
- tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
+ tts: vec![quoted::TokenTree::token(
+ if body.legacy { token::Semi } else { token::Comma },
+ def.span,
+ )],
separator: None,
kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
num_captures: 0,
/// A sequence separator.
pub struct SeqSep {
- /// The seperator token.
+ /// The separator token.
pub sep: Option<TokenKind>,
/// `true` if a trailing separator is allowed.
pub trailing_sep_allowed: bool,
let mut etc_span = None;
while self.token != token::CloseDelim(token::Brace) {
- let attrs = self.parse_outer_attributes()?;
+ let attrs = match self.parse_outer_attributes() {
+ Ok(attrs) => attrs,
+ Err(err) => {
+ if let Some(mut delayed) = delayed_err {
+ delayed.emit();
+ }
+ return Err(err);
+ },
+ };
let lo = self.token.span;
// check that a comma comes after every field
--- /dev/null
+// check-pass
+
+#![feature(decl_macro)]
+macro foo {
+ () => {},
+}
+
+fn main() {}
--- /dev/null
+// error-pattern: aborting due to 6 previous errors
+
+fn i(n{...,f #
--- /dev/null
+error: this file contains an un-closed delimiter
+ --> $DIR/issue-63135.rs:3:16
+ |
+LL | fn i(n{...,f #
+ | - - ^
+ | | |
+ | | un-closed delimiter
+ | un-closed delimiter
+
+error: expected field pattern, found `...`
+ --> $DIR/issue-63135.rs:3:8
+ |
+LL | fn i(n{...,f #
+ | ^^^ help: to omit remaining fields, use one fewer `.`: `..`
+
+error: expected `}`, found `,`
+ --> $DIR/issue-63135.rs:3:11
+ |
+LL | fn i(n{...,f #
+ | ---^
+ | | |
+ | | expected `}`
+ | `..` must be at the end and cannot have a trailing comma
+
+error: expected `[`, found `}`
+ --> $DIR/issue-63135.rs:3:15
+ |
+LL | fn i(n{...,f #
+ | ^ expected `[`
+
+error: expected `:`, found `)`
+ --> $DIR/issue-63135.rs:3:15
+ |
+LL | fn i(n{...,f #
+ | ^ expected `:`
+
+error: expected one of `->`, `where`, or `{`, found `<eof>`
+ --> $DIR/issue-63135.rs:3:15
+ |
+LL | fn i(n{...,f #
+ | ^ expected one of `->`, `where`, or `{` here
+
+error: aborting due to 6 previous errors
+