dedup free-form Unsupported errors; add macros for free-form UB and Unsupported cases

This commit is contained in:
Ralf Jung 2019-08-02 23:41:24 +02:00
parent 1b132a2f41
commit 1e24c73ae5
9 changed files with 41 additions and 49 deletions

View File

@ -363,7 +363,7 @@ impl fmt::Debug for UndefinedBehaviorInfo {
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum UnsupportedOpInfo<'tcx> {
/// Handle cases which for which we do not have a fixed variant.
Unimplemented(String),
Unsupported(String),
// -- Everything below is not classified yet --
FunctionAbiMismatch(Abi, Abi),
@ -390,20 +390,14 @@ pub enum UnsupportedOpInfo<'tcx> {
ReadUndefBytes(Size),
DeadLocal,
InvalidBoolOp(mir::BinOp),
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),
OutOfTls,
TlsOutOfBounds,
AbiViolation(String),
AlignmentCheckFailed {
required: Align,
has: Align,
@ -513,8 +507,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
initializer"),
AssumptionNotHeld =>
write!(f, "`assume` argument was false"),
InlineAsm =>
write!(f, "miri does not support inline assembly"),
ReallocateNonBasePtr =>
write!(f, "tried to reallocate with a pointer not to the beginning of an \
existing object"),
@ -537,10 +529,7 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
HeapAllocNonPowerOfTwoAlignment(_) =>
write!(f, "tried to re-, de-, or allocate heap memory with alignment that is \
not a power of two"),
MachineError(ref msg) |
Unimplemented(ref msg) |
AbiViolation(ref msg) |
Intrinsic(ref msg) =>
Unsupported(ref msg) =>
write!(f, "{}", msg),
}
}

View File

@ -50,6 +50,11 @@ macro_rules! throw_unsup {
($($tt:tt)*) => { return Err(err_unsup!($($tt)*).into()) };
}
#[macro_export]
macro_rules! throw_unsup_format {
($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) };
}
#[macro_export]
macro_rules! throw_inval {
($($tt:tt)*) => { return Err(err_inval!($($tt)*).into()) };
@ -60,6 +65,11 @@ macro_rules! throw_ub {
($($tt:tt)*) => { return Err(err_ub!($($tt)*).into()) };
}
#[macro_export]
macro_rules! throw_ub_format {
($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
}
#[macro_export]
macro_rules! throw_panic {
($($tt:tt)*) => { return Err(err_panic!($($tt)*).into()) };

View File

@ -181,17 +181,17 @@ fn eval_body_using_ecx<'mir, 'tcx>(
Ok(ret)
}
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalError {
fn into(self) -> InterpErrorInfo<'tcx> {
err_unsup!(MachineError(self.to_string())).into()
}
}
#[derive(Clone, Debug)]
enum ConstEvalError {
NeedsRfc(String),
}
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalError {
fn into(self) -> InterpErrorInfo<'tcx> {
err_unsup!(Unsupported(self.to_string())).into()
}
}
impl fmt::Display for ConstEvalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::ConstEvalError::*;
@ -341,7 +341,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
debug!("eval_fn_call: {:?}", instance);
// Only check non-glue functions
if let ty::InstanceDef::Item(def_id) = instance.def {
// Execution might have wandered off into other crates, so we cannot to a stability-
// Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const
// at all.
if !ecx.tcx.is_const_fn_raw(def_id) {
@ -352,7 +352,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
ecx.goto_block(ret)?; // fully evaluated and done
Ok(None)
} else {
throw_unsup!(MachineError(format!("calling non-const function `{}`", instance)))
throw_unsup_format!("calling non-const function `{}`", instance)
};
}
}

View File

@ -199,7 +199,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
},
// Casts to bool are not permitted by rustc, no need to handle them here.
_ => throw_unsup!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
_ => bug!("invalid int to {:?} cast", dest_layout.ty),
}
}

View File

@ -98,11 +98,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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(err_unsup!(TypeNotPrimitive(ty)))?,
_ => throw_unsup!(TypeNotPrimitive(ty)),
};
let out_val = if intrinsic_name.ends_with("_nonzero") {
if bits == 0 {
throw_unsup!(Intrinsic(format!("{} called on 0", intrinsic_name)))
throw_ub_format!("`{}` called on 0", intrinsic_name);
}
numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
} else {
@ -187,10 +187,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
if overflowed {
let layout = self.layout_of(substs.type_at(0))?;
let r_val = r.to_scalar()?.to_bits(layout.size)?;
throw_unsup!(
Intrinsic(format!("Overflowing shift by {} in {}", r_val, intrinsic_name))
)
let r_val = r.to_scalar()?.to_bits(layout.size)?;
throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name);
}
self.write_scalar(val, dest)?;
}

View File

@ -66,9 +66,9 @@ impl<'tcx, Other> FnVal<'tcx, Other> {
match self {
FnVal::Instance(instance) =>
Ok(instance),
FnVal::Other(_) => throw_unsup!(MachineError(format!(
"Expected instance function pointer, got 'other' pointer"
))),
FnVal::Other(_) => throw_unsup_format!(
"'foreign' function pointers are not supported in this context"
),
}
}
}
@ -834,9 +834,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
if (src.offset <= dest.offset && src.offset + size > dest.offset) ||
(dest.offset <= src.offset && dest.offset + size > src.offset)
{
throw_unsup!(Intrinsic(
"copy_nonoverlapping called on overlapping ranges".to_string(),
))
throw_ub_format!(
"copy_nonoverlapping called on overlapping ranges"
)
}
}

View File

@ -147,15 +147,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// For the remaining ops, the types must be the same on both sides
if left_layout.ty != right_layout.ty {
let msg = format!(
"unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bug!(
"invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op,
l,
left_layout.ty,
r,
right_layout.ty
);
throw_unsup!(Unimplemented(msg))
l, left_layout.ty,
r, right_layout.ty,
)
}
// Operations that need special treatment for signed integers
@ -243,14 +240,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
_ => {
let msg = format!(
"unimplemented binary op {:?}: {:?}, {:?} (both {:?})",
bug!(
"invalid binary op {:?}: {:?}, {:?} (both {:?})",
bin_op,
l,
r,
right_layout.ty,
);
throw_unsup!(Unimplemented(msg))
)
}
};

View File

@ -121,7 +121,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// size of MIR constantly.
Nop => {}
InlineAsm { .. } => throw_unsup!(InlineAsm),
InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
}
self.stack[frame_idx].stmt += 1;

View File

@ -88,8 +88,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(FnVal::Instance(self.resolve(def_id, substs)?), sig.abi())
},
_ => {
let msg = format!("can't handle callee of type {:?}", func.layout.ty);
throw_unsup!(Unimplemented(msg))
bug!("invalid callee of type {:?}", func.layout.ty)
}
};
let args = self.eval_operands(args)?;