address nits
This commit is contained in:
parent
6c78fa822a
commit
f96208ca5b
@ -517,7 +517,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
|
||||
InvalidMemoryAccess |
|
||||
InvalidFunctionPointer |
|
||||
InvalidBool |
|
||||
InvalidDiscriminant |
|
||||
InvalidNullPointerUsage |
|
||||
ReadPointerAsBytes |
|
||||
ReadBytesAsPointer |
|
||||
@ -550,6 +549,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic |
|
||||
InfiniteLoop => {}
|
||||
InvalidDiscriminant(val) => val.hash_stable(hcx, hasher),
|
||||
Panic { ref msg, ref file, line, col } => {
|
||||
msg.hash_stable(hcx, hasher);
|
||||
file.hash_stable(hcx, hasher);
|
||||
|
@ -190,7 +190,7 @@ pub enum EvalErrorKind<'tcx, O> {
|
||||
InvalidMemoryAccess,
|
||||
InvalidFunctionPointer,
|
||||
InvalidBool,
|
||||
InvalidDiscriminant,
|
||||
InvalidDiscriminant(u128),
|
||||
PointerOutOfBounds {
|
||||
ptr: Pointer,
|
||||
access: bool,
|
||||
@ -302,8 +302,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
|
||||
"tried to use a function pointer after offsetting it",
|
||||
InvalidBool =>
|
||||
"invalid boolean value read",
|
||||
InvalidDiscriminant =>
|
||||
"invalid enum discriminant value read or written",
|
||||
InvalidDiscriminant(..) =>
|
||||
"invalid enum discriminant value read",
|
||||
PointerOutOfBounds { .. } =>
|
||||
"pointer offset outside bounds of allocation",
|
||||
InvalidNullPointerUsage =>
|
||||
@ -488,6 +488,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
|
||||
align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
|
||||
Panic { ref msg, line, col, ref file } =>
|
||||
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
|
||||
InvalidDiscriminant(val) =>
|
||||
write!(f, "encountered invalid enum discriminant {}", val),
|
||||
_ => write!(f, "{}", self.description()),
|
||||
}
|
||||
}
|
||||
|
@ -498,7 +498,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
|
||||
InvalidMemoryAccess => InvalidMemoryAccess,
|
||||
InvalidFunctionPointer => InvalidFunctionPointer,
|
||||
InvalidBool => InvalidBool,
|
||||
InvalidDiscriminant => InvalidDiscriminant,
|
||||
InvalidDiscriminant(val) => InvalidDiscriminant(val),
|
||||
PointerOutOfBounds {
|
||||
ptr,
|
||||
access,
|
||||
|
@ -585,7 +585,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
.expect("tagged layout for non adt")
|
||||
.discriminants(self.tcx.tcx)
|
||||
.position(|var| var.val == real_discr)
|
||||
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant)?;
|
||||
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(real_discr))?;
|
||||
(real_discr, index)
|
||||
},
|
||||
layout::Variants::NicheFilling {
|
||||
|
@ -48,111 +48,100 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
/// Returns the result of the specified operation and whether it overflowed.
|
||||
pub fn binary_op(
|
||||
fn binary_char_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
|
||||
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
|
||||
l: char,
|
||||
r: char,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
let left = left.to_scalar()?;
|
||||
let right = right.to_scalar()?;
|
||||
let res = match bin_op {
|
||||
Eq => l == r,
|
||||
Ne => l != r,
|
||||
Lt => l < r,
|
||||
Le => l <= r,
|
||||
Gt => l > r,
|
||||
Ge => l >= r,
|
||||
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
||||
};
|
||||
return Ok((Scalar::from_bool(res), false));
|
||||
}
|
||||
|
||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
|
||||
fn binary_bool_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
l: bool,
|
||||
r: bool,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
// Handle non-integer operations
|
||||
if let ty::Char = left_layout.ty.sty {
|
||||
assert_eq!(right_layout.ty.sty, ty::Char);
|
||||
let l = left.to_char()?;
|
||||
let r = right.to_char()?;
|
||||
let res = match bin_op {
|
||||
Eq => l == r,
|
||||
Ne => l != r,
|
||||
Lt => l < r,
|
||||
Le => l <= r,
|
||||
Gt => l > r,
|
||||
Ge => l >= r,
|
||||
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
||||
};
|
||||
return Ok((Scalar::from_bool(res), false));
|
||||
}
|
||||
if let ty::Bool = left_layout.ty.sty {
|
||||
assert_eq!(right_layout.ty.sty, ty::Bool);
|
||||
let l = left.to_bool()?;
|
||||
let r = right.to_bool()?;
|
||||
let res = match bin_op {
|
||||
Eq => l == r,
|
||||
Ne => l != r,
|
||||
Lt => l < r,
|
||||
Le => l <= r,
|
||||
Gt => l > r,
|
||||
Ge => l >= r,
|
||||
BitAnd => l & r,
|
||||
BitOr => l | r,
|
||||
BitXor => l ^ r,
|
||||
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
||||
};
|
||||
return Ok((Scalar::from_bool(res), false));
|
||||
}
|
||||
if let ty::Float(fty) = left_layout.ty.sty {
|
||||
let l = left.to_bits(left_layout.size)?;
|
||||
let r = right.to_bits(right_layout.size)?;
|
||||
assert_eq!(right_layout.ty.sty, ty::Float(fty));
|
||||
macro_rules! float_math {
|
||||
($ty:path, $size:expr) => {{
|
||||
let l = <$ty>::from_bits(l);
|
||||
let r = <$ty>::from_bits(r);
|
||||
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
|
||||
bits: res.value.to_bits(),
|
||||
size: $size,
|
||||
};
|
||||
let val = match bin_op {
|
||||
Eq => Scalar::from_bool(l == r),
|
||||
Ne => Scalar::from_bool(l != r),
|
||||
Lt => Scalar::from_bool(l < r),
|
||||
Le => Scalar::from_bool(l <= r),
|
||||
Gt => Scalar::from_bool(l > r),
|
||||
Ge => Scalar::from_bool(l >= r),
|
||||
Add => bitify(l + r),
|
||||
Sub => bitify(l - r),
|
||||
Mul => bitify(l * r),
|
||||
Div => bitify(l / r),
|
||||
Rem => bitify(l % r),
|
||||
_ => bug!("invalid float op: `{:?}`", bin_op),
|
||||
};
|
||||
return Ok((val, false));
|
||||
}};
|
||||
}
|
||||
match fty {
|
||||
FloatTy::F32 => float_math!(Single, 4),
|
||||
FloatTy::F64 => float_math!(Double, 8),
|
||||
}
|
||||
}
|
||||
// Only integers left
|
||||
#[inline]
|
||||
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
|
||||
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));
|
||||
let res = match bin_op {
|
||||
Eq => l == r,
|
||||
Ne => l != r,
|
||||
Lt => l < r,
|
||||
Le => l <= r,
|
||||
Gt => l > r,
|
||||
Ge => l >= r,
|
||||
BitAnd => l & r,
|
||||
BitOr => l | r,
|
||||
BitXor => l ^ r,
|
||||
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
||||
};
|
||||
return Ok((Scalar::from_bool(res), false));
|
||||
}
|
||||
|
||||
// Handle operations that support pointers
|
||||
if let Some(handled) =
|
||||
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
|
||||
{
|
||||
return Ok(handled);
|
||||
}
|
||||
fn binary_float_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
fty: FloatTy,
|
||||
// passing in raw bits
|
||||
l: u128,
|
||||
r: u128,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
// From now on, everything must be bytes, no pointer values
|
||||
// (this is independent of the type)
|
||||
let l = left.to_bits(left_layout.size)?;
|
||||
let r = right.to_bits(right_layout.size)?;
|
||||
macro_rules! float_math {
|
||||
($ty:path, $size:expr) => {{
|
||||
let l = <$ty>::from_bits(l);
|
||||
let r = <$ty>::from_bits(r);
|
||||
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
|
||||
bits: res.value.to_bits(),
|
||||
size: $size,
|
||||
};
|
||||
let val = match bin_op {
|
||||
Eq => Scalar::from_bool(l == r),
|
||||
Ne => Scalar::from_bool(l != r),
|
||||
Lt => Scalar::from_bool(l < r),
|
||||
Le => Scalar::from_bool(l <= r),
|
||||
Gt => Scalar::from_bool(l > r),
|
||||
Ge => Scalar::from_bool(l >= r),
|
||||
Add => bitify(l + r),
|
||||
Sub => bitify(l - r),
|
||||
Mul => bitify(l * r),
|
||||
Div => bitify(l / r),
|
||||
Rem => bitify(l % r),
|
||||
_ => bug!("invalid float op: `{:?}`", bin_op),
|
||||
};
|
||||
return Ok((val, false));
|
||||
}};
|
||||
}
|
||||
match fty {
|
||||
FloatTy::F32 => float_math!(Single, 4),
|
||||
FloatTy::F64 => float_math!(Double, 8),
|
||||
}
|
||||
}
|
||||
|
||||
fn binary_int_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
// passing in raw bits
|
||||
l: u128,
|
||||
left_layout: TyLayout<'tcx>,
|
||||
r: u128,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
// Shift ops can have an RHS with a different numeric type.
|
||||
if bin_op == Shl || bin_op == Shr {
|
||||
@ -189,11 +178,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, '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 binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
"unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op,
|
||||
left,
|
||||
l,
|
||||
left_layout.ty,
|
||||
right,
|
||||
r,
|
||||
right_layout.ty
|
||||
);
|
||||
return err!(Unimplemented(msg));
|
||||
@ -289,11 +278,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
|
||||
_ => {
|
||||
let msg = format!(
|
||||
"unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
"unimplemented binary op {:?}: {:?}, {:?} (both {:?})",
|
||||
bin_op,
|
||||
left,
|
||||
left_layout.ty,
|
||||
right,
|
||||
l,
|
||||
r,
|
||||
right_layout.ty,
|
||||
);
|
||||
return err!(Unimplemented(msg));
|
||||
@ -303,6 +291,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
Ok((val, false))
|
||||
}
|
||||
|
||||
/// Returns the result of the specified operation and whether it overflowed.
|
||||
pub fn binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
|
||||
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
let left = left.to_scalar()?;
|
||||
let right = right.to_scalar()?;
|
||||
|
||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
|
||||
|
||||
match left_layout.ty.sty {
|
||||
ty::Char => {
|
||||
assert_eq!(left_layout.ty, right_layout.ty);
|
||||
let l = left.to_char()?;
|
||||
let r = right.to_char()?;
|
||||
self.binary_char_op(bin_op, l, r)
|
||||
}
|
||||
ty::Bool => {
|
||||
assert_eq!(left_layout.ty, right_layout.ty);
|
||||
let l = left.to_bool()?;
|
||||
let r = right.to_bool()?;
|
||||
self.binary_bool_op(bin_op, l, r)
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
assert_eq!(left_layout.ty, right_layout.ty);
|
||||
let l = left.to_bits(left_layout.size)?;
|
||||
let r = right.to_bits(right_layout.size)?;
|
||||
self.binary_float_op(bin_op, fty, l, r)
|
||||
}
|
||||
_ => {
|
||||
// Must be integer(-like) types
|
||||
#[inline]
|
||||
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
|
||||
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));
|
||||
|
||||
// Handle operations that support pointer values
|
||||
if let Some(handled) =
|
||||
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
|
||||
{
|
||||
return Ok(handled);
|
||||
}
|
||||
|
||||
// Everything else only works with "proper" bits
|
||||
let l = left.to_bits(left_layout.size)?;
|
||||
let r = right.to_bits(right_layout.size)?;
|
||||
self.binary_int_op(bin_op, l, left_layout, r, right_layout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unary_op(
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
|
@ -660,7 +660,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
// a fake pointer? Are we even called for ZST?
|
||||
|
||||
// We need the layout of the local. We can NOT use the layout we got,
|
||||
// that might e.g. be a downcast variant!
|
||||
// that might e.g. be an inner field of a struct with `Scalar` layout,
|
||||
// that has different alignment than the outer field.
|
||||
let local_layout = self.layout_of_local(frame, local)?;
|
||||
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
|
||||
self.write_value_to_mplace(value, ptr)?;
|
||||
@ -695,15 +696,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
) -> EvalResult<'tcx> {
|
||||
match dest.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
if index != variant_index {
|
||||
return err!(InvalidDiscriminant);
|
||||
}
|
||||
assert_eq!(index, variant_index);
|
||||
}
|
||||
layout::Variants::Tagged { ref tag, .. } => {
|
||||
let adt_def = dest.layout.ty.ty_adt_def().unwrap();
|
||||
if variant_index >= adt_def.variants.len() {
|
||||
return err!(InvalidDiscriminant);
|
||||
}
|
||||
assert!(variant_index < adt_def.variants.len());
|
||||
let discr_val = adt_def
|
||||
.discriminant_for_variant(*self.tcx, variant_index)
|
||||
.val;
|
||||
@ -727,9 +724,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
niche_start,
|
||||
..
|
||||
} => {
|
||||
if variant_index >= dest.layout.ty.ty_adt_def().unwrap().variants.len() {
|
||||
return err!(InvalidDiscriminant);
|
||||
}
|
||||
assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
|
||||
if variant_index != dataful_variant {
|
||||
let niche_dest =
|
||||
self.place_field(dest, 0)?;
|
||||
|
@ -276,7 +276,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
/// Call this function -- pushing the stack frame and initializing the arguments.
|
||||
/// `sig` is ptional in case of FnPtr/FnDef -- but mandatory for closures!
|
||||
/// `sig` is optional in case of FnPtr/FnDef -- but mandatory for closures!
|
||||
fn eval_fn_call(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
@ -462,7 +462,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
|
||||
};
|
||||
|
||||
let ty = self.tcx.mk_tup((&[] as &[ty::Ty<'tcx>]).iter()); // return type is ()
|
||||
let ty = self.tcx.mk_nil(); // return type is ()
|
||||
let dest = PlaceTy::null(&self, self.layout_of(ty)?);
|
||||
|
||||
self.eval_fn_call(
|
||||
|
@ -208,10 +208,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
layout::Variants::Tagged { .. } => {
|
||||
let variant = match self.read_discriminant(dest) {
|
||||
Ok(res) => res.1,
|
||||
Err(_) =>
|
||||
return validation_failure!(
|
||||
"invalid enum discriminant", path
|
||||
),
|
||||
Err(err) => match err.kind {
|
||||
EvalErrorKind::InvalidDiscriminant(val) =>
|
||||
return validation_failure!(
|
||||
format!("invalid enum discriminant {}", val), path
|
||||
),
|
||||
_ =>
|
||||
return validation_failure!(
|
||||
format!("non-integer enum discriminant"), path
|
||||
),
|
||||
}
|
||||
};
|
||||
let inner_dest = self.operand_downcast(dest, variant)?;
|
||||
// Put the variant projection onto the path, as a field
|
||||
|
@ -170,7 +170,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||
| DoubleFree
|
||||
| InvalidFunctionPointer
|
||||
| InvalidBool
|
||||
| InvalidDiscriminant
|
||||
| InvalidDiscriminant(..)
|
||||
| PointerOutOfBounds { .. }
|
||||
| InvalidNullPointerUsage
|
||||
| MemoryLockViolation { .. }
|
||||
|
@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
|
||||
LL | | Union { usize: &BAR }.foo,
|
||||
LL | | Union { usize: &BAR }.bar,
|
||||
LL | | )};
|
||||
| |___^ type validation failed: encountered invalid enum discriminant at .1.<deref>
|
||||
| |___^ type validation failed: encountered invalid enum discriminant 5 at .1.<deref>
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
|
@ -2,7 +2,7 @@ error[E0080]: this constant likely exhibits undefined behavior
|
||||
--> $DIR/ub-enum.rs:22:1
|
||||
|
|
||||
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer enum discriminant
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
@ -10,7 +10,7 @@ error[E0080]: this constant likely exhibits undefined behavior
|
||||
--> $DIR/ub-enum.rs:35:1
|
||||
|
|
||||
LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant 0
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user