Rollup merge of #55645 - RalfJung:validity-range-inclusive, r=oli-obk
do not print wrapping ranges like normal ranges in validity diagnostics
This commit is contained in:
commit
4e86576277
27 changed files with 1057 additions and 642 deletions
|
|
@ -15,7 +15,7 @@ use ty::{Ty, layout};
|
|||
use ty::layout::{Size, Align, LayoutError};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use super::Pointer;
|
||||
use super::{Pointer, Scalar};
|
||||
|
||||
use backtrace::Backtrace;
|
||||
|
||||
|
|
@ -240,7 +240,7 @@ pub enum EvalErrorKind<'tcx, O> {
|
|||
InvalidMemoryAccess,
|
||||
InvalidFunctionPointer,
|
||||
InvalidBool,
|
||||
InvalidDiscriminant(u128),
|
||||
InvalidDiscriminant(Scalar),
|
||||
PointerOutOfBounds {
|
||||
ptr: Pointer,
|
||||
access: bool,
|
||||
|
|
|
|||
|
|
@ -91,12 +91,33 @@ pub trait PointerArithmetic: layout::HasDataLayout {
|
|||
}
|
||||
|
||||
//// Trunace the given value to the pointer size; also return whether there was an overflow
|
||||
#[inline]
|
||||
fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
|
||||
let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
|
||||
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_offset(val, i);
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
|
||||
let (res, over1) = val.overflowing_add(i);
|
||||
let (res, over2) = self.truncate_to_ptr(u128::from(res));
|
||||
(res, over1 || over2)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
// Overflow checking only works properly on the range from -u64 to +u64.
|
||||
#[inline]
|
||||
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
|
||||
// FIXME: is it possible to over/underflow here?
|
||||
if i < 0 {
|
||||
|
|
@ -108,26 +129,6 @@ pub trait PointerArithmetic: layout::HasDataLayout {
|
|||
self.overflowing_offset(val, i as u64)
|
||||
}
|
||||
}
|
||||
|
||||
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
|
||||
let (res, over1) = val.overflowing_add(i);
|
||||
let (res, over2) = self.truncate_to_ptr(res as u128);
|
||||
(res, over1 || over2)
|
||||
}
|
||||
|
||||
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_signed_offset(val, i as i128);
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_offset(val, i);
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
fn wrapping_signed_offset(&self, val: u64, i: i64) -> u64 {
|
||||
self.overflowing_signed_offset(val, i as i128).0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: layout::HasDataLayout> PointerArithmetic for T {}
|
||||
|
|
@ -176,32 +177,7 @@ impl<'tcx, Tag> Pointer<Tag> {
|
|||
Pointer { alloc_id, offset, tag }
|
||||
}
|
||||
|
||||
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
|
||||
Pointer::new_with_tag(
|
||||
self.alloc_id,
|
||||
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
|
||||
self.tag,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
|
||||
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
|
||||
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
|
||||
}
|
||||
|
||||
pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
|
||||
Ok(Pointer::new_with_tag(
|
||||
self.alloc_id,
|
||||
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
|
||||
self.tag,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
|
||||
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
|
||||
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
|
||||
Ok(Pointer::new_with_tag(
|
||||
self.alloc_id,
|
||||
|
|
@ -211,6 +187,37 @@ impl<'tcx, Tag> Pointer<Tag> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
|
||||
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
|
||||
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
|
||||
self.overflowing_offset(i, cx).0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
|
||||
Ok(Pointer::new_with_tag(
|
||||
self.alloc_id,
|
||||
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
|
||||
self.tag,
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
|
||||
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
|
||||
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
|
||||
self.overflowing_signed_offset(i128::from(i), cx).0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn erase_tag(self) -> Pointer {
|
||||
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(unknown_lints)]
|
||||
use std::fmt;
|
||||
|
||||
use ty::layout::{HasDataLayout, Size};
|
||||
use ty::subst::Substs;
|
||||
|
|
@ -99,6 +99,15 @@ pub enum Scalar<Tag=(), Id=AllocId> {
|
|||
Ptr(Pointer<Tag, Id>),
|
||||
}
|
||||
|
||||
impl<Tag> fmt::Display for Scalar<Tag> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Scalar::Ptr(_) => write!(f, "a pointer"),
|
||||
Scalar::Bits { bits, .. } => write!(f, "{}", bits),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Scalar<()> {
|
||||
#[inline]
|
||||
pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
|
||||
|
|
@ -133,21 +142,6 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
Scalar::Bits { bits: 0, size: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
|
||||
let dl = cx.data_layout();
|
||||
match self {
|
||||
Scalar::Bits { bits, size } => {
|
||||
assert_eq!(size as u64, dl.pointer_size.bytes());
|
||||
Ok(Scalar::Bits {
|
||||
bits: dl.signed_offset(bits as u64, i)? as u128,
|
||||
size,
|
||||
})
|
||||
}
|
||||
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
|
||||
let dl = cx.data_layout();
|
||||
|
|
@ -163,6 +157,36 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
|
||||
let dl = cx.data_layout();
|
||||
match self {
|
||||
Scalar::Bits { bits, size } => {
|
||||
assert_eq!(size as u64, dl.pointer_size.bytes());
|
||||
Scalar::Bits {
|
||||
bits: dl.overflowing_offset(bits as u64, i.bytes()).0 as u128,
|
||||
size,
|
||||
}
|
||||
}
|
||||
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_offset(i, dl)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
|
||||
let dl = cx.data_layout();
|
||||
match self {
|
||||
Scalar::Bits { bits, size } => {
|
||||
assert_eq!(size as u64, dl.pointer_size().bytes());
|
||||
Ok(Scalar::Bits {
|
||||
bits: dl.signed_offset(bits as u64, i)? as u128,
|
||||
size,
|
||||
})
|
||||
}
|
||||
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
|
||||
let dl = cx.data_layout();
|
||||
|
|
@ -170,7 +194,7 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
Scalar::Bits { bits, size } => {
|
||||
assert_eq!(size as u64, dl.pointer_size.bytes());
|
||||
Scalar::Bits {
|
||||
bits: dl.wrapping_signed_offset(bits as u64, i) as u128,
|
||||
bits: dl.overflowing_signed_offset(bits as u64, i128::from(i)).0 as u128,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
|
@ -178,6 +202,19 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns this pointers offset from the allocation base, or from NULL (for
|
||||
/// integer pointers).
|
||||
#[inline]
|
||||
pub fn get_ptr_offset(self, cx: &impl HasDataLayout) -> Size {
|
||||
match self {
|
||||
Scalar::Bits { bits, size } => {
|
||||
assert_eq!(size as u64, cx.pointer_size().bytes());
|
||||
Size::from_bytes(bits as u64)
|
||||
}
|
||||
Scalar::Ptr(ptr) => ptr.offset,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_null_ptr(self, cx: &impl HasDataLayout) -> bool {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -539,10 +539,10 @@ fn validate_const<'a, 'tcx>(
|
|||
let val = (|| {
|
||||
let op = ecx.const_to_op(constant)?;
|
||||
let mut ref_tracking = RefTracking::new(op);
|
||||
while let Some((op, mut path)) = ref_tracking.todo.pop() {
|
||||
while let Some((op, path)) = ref_tracking.todo.pop() {
|
||||
ecx.validate_operand(
|
||||
op,
|
||||
&mut path,
|
||||
path,
|
||||
Some(&mut ref_tracking),
|
||||
/* const_mode */ true,
|
||||
)?;
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
|||
// return place is always a local and then this cannot happen.
|
||||
self.validate_operand(
|
||||
self.place_to_op(return_place)?,
|
||||
&mut vec![],
|
||||
vec![],
|
||||
None,
|
||||
/*const_mode*/false,
|
||||
)?;
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ use std::hash::Hash;
|
|||
|
||||
use rustc::hir::{self, def_id::DefId};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty, layout::{Size, TyLayout}, query::TyCtxtAt};
|
||||
use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt};
|
||||
|
||||
use super::{
|
||||
Allocation, AllocId, EvalResult, Scalar,
|
||||
EvalContext, PlaceTy, OpTy, Pointer, MemPlace, MemoryKind,
|
||||
EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
|
||||
};
|
||||
|
||||
/// Whether this kind of memory is allowed to leak
|
||||
|
|
@ -217,26 +217,22 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
|||
#[inline]
|
||||
fn tag_reference(
|
||||
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
place: MemPlace<Self::PointerTag>,
|
||||
_ty: Ty<'tcx>,
|
||||
_size: Size,
|
||||
place: MPlaceTy<'tcx, Self::PointerTag>,
|
||||
_mutability: Option<hir::Mutability>,
|
||||
) -> EvalResult<'tcx, MemPlace<Self::PointerTag>> {
|
||||
Ok(place)
|
||||
) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
|
||||
Ok(place.ptr)
|
||||
}
|
||||
|
||||
/// Executed when evaluating the `*` operator: Following a reference.
|
||||
/// This has the change to adjust the tag. It should not change anything else!
|
||||
/// This has the chance to adjust the tag. It should not change anything else!
|
||||
/// `mutability` can be `None` in case a raw ptr is being dereferenced.
|
||||
#[inline]
|
||||
fn tag_dereference(
|
||||
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
place: MemPlace<Self::PointerTag>,
|
||||
_ty: Ty<'tcx>,
|
||||
_size: Size,
|
||||
place: MPlaceTy<'tcx, Self::PointerTag>,
|
||||
_mutability: Option<hir::Mutability>,
|
||||
) -> EvalResult<'tcx, MemPlace<Self::PointerTag>> {
|
||||
Ok(place)
|
||||
) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
|
||||
Ok(place.ptr)
|
||||
}
|
||||
|
||||
/// Execute a validation operation
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ mod terminator;
|
|||
mod traits;
|
||||
mod validity;
|
||||
mod intrinsics;
|
||||
mod visitor;
|
||||
|
||||
pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
||||
|
||||
|
|
@ -38,4 +39,6 @@ pub use self::machine::{Machine, AllocMap, MayLeak};
|
|||
|
||||
pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy};
|
||||
|
||||
pub use self::visitor::ValueVisitor;
|
||||
|
||||
pub use self::validity::RefTracking;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
//! All high-level functions to read from memory work on operands as sources.
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
|
||||
use rustc::{mir, ty};
|
||||
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
|
||||
|
|
@ -36,6 +37,15 @@ impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ScalarMaybeUndef::Undef => write!(f, "uninitialized bytes"),
|
||||
ScalarMaybeUndef::Scalar(s) => write!(f, "{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ScalarMaybeUndef<()> {
|
||||
#[inline]
|
||||
pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
|
||||
|
|
@ -732,8 +742,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
Ok(match rval.layout.variants {
|
||||
layout::Variants::Single { .. } => bug!(),
|
||||
layout::Variants::Tagged { .. } => {
|
||||
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())),
|
||||
};
|
||||
let real_discr = if discr_val.layout.ty.is_signed() {
|
||||
let i = raw_discr.to_bits(discr_val.layout.size)? as i128;
|
||||
let i = bits_discr as i128;
|
||||
// going from layout tag type to typeck discriminant type
|
||||
// requires first sign extending with the layout discriminant
|
||||
let shift = 128 - discr_val.layout.size.bits();
|
||||
|
|
@ -748,7 +762,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
let truncatee = sexted as u128;
|
||||
(truncatee << shift) >> shift
|
||||
} else {
|
||||
raw_discr.to_bits(discr_val.layout.size)?
|
||||
bits_discr
|
||||
};
|
||||
// Make sure we catch invalid discriminants
|
||||
let index = rval.layout.ty
|
||||
|
|
@ -756,7 +770,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, '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(real_discr))?;
|
||||
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?;
|
||||
(real_discr, index)
|
||||
},
|
||||
layout::Variants::NicheFilling {
|
||||
|
|
|
|||
|
|
@ -278,11 +278,9 @@ where
|
|||
let meta = val.to_meta()?;
|
||||
let ptr = val.to_scalar_ptr()?;
|
||||
let mplace = MemPlace { ptr, align, meta };
|
||||
let mut mplace = MPlaceTy { mplace, layout };
|
||||
// Pointer tag tracking might want to adjust the tag.
|
||||
let mplace = if M::ENABLE_PTR_TRACKING_HOOKS {
|
||||
let (size, _) = self.size_and_align_of(meta, layout)?
|
||||
// for extern types, just cover what we can
|
||||
.unwrap_or_else(|| layout.size_and_align());
|
||||
if M::ENABLE_PTR_TRACKING_HOOKS {
|
||||
let mutbl = match val.layout.ty.sty {
|
||||
// `builtin_deref` considers boxes immutable, that's useless for our purposes
|
||||
ty::Ref(_, _, mutbl) => Some(mutbl),
|
||||
|
|
@ -290,11 +288,10 @@ where
|
|||
ty::RawPtr(_) => None,
|
||||
_ => bug!("Unexpected pointer type {}", val.layout.ty.sty),
|
||||
};
|
||||
M::tag_dereference(self, mplace, pointee_type, size, mutbl)?
|
||||
} else {
|
||||
mplace
|
||||
};
|
||||
Ok(MPlaceTy { mplace, layout })
|
||||
mplace.mplace.ptr = M::tag_dereference(self, mplace, mutbl)?;
|
||||
}
|
||||
// Done
|
||||
Ok(mplace)
|
||||
}
|
||||
|
||||
/// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
|
||||
|
|
@ -302,18 +299,13 @@ where
|
|||
/// `mutbl` indicates whether we are create a shared or mutable ref, or a raw pointer (`None`).
|
||||
pub fn create_ref(
|
||||
&mut self,
|
||||
place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
mut place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
mutbl: Option<hir::Mutability>,
|
||||
) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
|
||||
// Pointer tag tracking might want to adjust the tag
|
||||
let place = if M::ENABLE_PTR_TRACKING_HOOKS {
|
||||
let (size, _) = self.size_and_align_of_mplace(place)?
|
||||
// for extern types, just cover what we can
|
||||
.unwrap_or_else(|| place.layout.size_and_align());
|
||||
M::tag_reference(self, *place, place.layout.ty, size, mutbl)?
|
||||
} else {
|
||||
*place
|
||||
};
|
||||
if M::ENABLE_PTR_TRACKING_HOOKS {
|
||||
place.mplace.ptr = M::tag_reference(self, place, mutbl)?
|
||||
}
|
||||
Ok(match place.meta {
|
||||
None => Immediate::Scalar(place.ptr.into()),
|
||||
Some(meta) => Immediate::ScalarPair(place.ptr.into(), meta.into()),
|
||||
|
|
@ -489,6 +481,8 @@ where
|
|||
|
||||
/// Get the place of a field inside the place, and also the field's type.
|
||||
/// Just a convenience function, but used quite a bit.
|
||||
/// This is the only projection that might have a side-effect: We cannot project
|
||||
/// into the field of a local `ScalarPair`, we have to first allocate it.
|
||||
pub fn place_field(
|
||||
&mut self,
|
||||
base: PlaceTy<'tcx, M::PointerTag>,
|
||||
|
|
@ -501,7 +495,7 @@ where
|
|||
}
|
||||
|
||||
pub fn place_downcast(
|
||||
&mut self,
|
||||
&self,
|
||||
base: PlaceTy<'tcx, M::PointerTag>,
|
||||
variant: usize,
|
||||
) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
||||
|
|
@ -643,7 +637,7 @@ where
|
|||
|
||||
if M::enforce_validity(self) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
|
||||
self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -765,7 +759,7 @@ where
|
|||
|
||||
if M::enforce_validity(self) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
|
||||
self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -843,7 +837,7 @@ where
|
|||
|
||||
if M::enforce_validity(self) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
|
||||
self.validate_operand(dest.into(), vec![], None, /*const_mode*/false)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
320
src/librustc_mir/interpret/visitor.rs
Normal file
320
src/librustc_mir/interpret/visitor.rs
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
|
||||
//! types until we arrive at the leaves, with custom handling for primitive types.
|
||||
|
||||
use rustc::ty::layout::{self, TyLayout};
|
||||
use rustc::ty;
|
||||
use rustc::mir::interpret::{
|
||||
EvalResult,
|
||||
};
|
||||
|
||||
use super::{
|
||||
Machine, EvalContext, MPlaceTy, OpTy, ImmTy,
|
||||
};
|
||||
|
||||
// A thing that we can project into, and that has a layout.
|
||||
// This wouldn't have to depend on `Machine` but with the current type inference,
|
||||
// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
|
||||
pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
|
||||
{
|
||||
/// Get this value's layout.
|
||||
fn layout(&self) -> TyLayout<'tcx>;
|
||||
|
||||
/// Make this into an `OpTy`.
|
||||
fn to_op(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>;
|
||||
|
||||
/// Create this from an `MPlaceTy`.
|
||||
fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;
|
||||
|
||||
/// Project to the given enum variant.
|
||||
fn project_downcast(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
variant: usize,
|
||||
) -> EvalResult<'tcx, Self>;
|
||||
|
||||
/// Project to the n-th field.
|
||||
fn project_field(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
field: u64,
|
||||
) -> EvalResult<'tcx, Self>;
|
||||
}
|
||||
|
||||
// Operands and memory-places are both values.
|
||||
// Places in general are not due to `place_field` having to do `force_allocation`.
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
|
||||
for OpTy<'tcx, M::PointerTag>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyLayout<'tcx> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn to_op(
|
||||
self,
|
||||
_ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
|
||||
mplace.into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn project_downcast(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
variant: usize,
|
||||
) -> EvalResult<'tcx, Self> {
|
||||
ecx.operand_downcast(self, variant)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn project_field(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
field: u64,
|
||||
) -> EvalResult<'tcx, Self> {
|
||||
ecx.operand_field(self, field)
|
||||
}
|
||||
}
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
|
||||
for MPlaceTy<'tcx, M::PointerTag>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyLayout<'tcx> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn to_op(
|
||||
self,
|
||||
_ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
Ok(self.into())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
|
||||
mplace
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn project_downcast(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
variant: usize,
|
||||
) -> EvalResult<'tcx, Self> {
|
||||
ecx.mplace_downcast(self, variant)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn project_field(
|
||||
self,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
|
||||
field: u64,
|
||||
) -> EvalResult<'tcx, Self> {
|
||||
ecx.mplace_field(self, field)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_value_visitor {
|
||||
($visitor_trait_name:ident, $($mutability:ident)*) => {
|
||||
// How to traverse a value and what to do when we are at the leaves.
|
||||
pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
|
||||
type V: Value<'a, 'mir, 'tcx, M>;
|
||||
|
||||
/// The visitor must have an `EvalContext` in it.
|
||||
fn ecx(&$($mutability)* self)
|
||||
-> &$($mutability)* EvalContext<'a, 'mir, 'tcx, M>;
|
||||
|
||||
// Recursive actions, ready to be overloaded.
|
||||
/// Visit the given value, dispatching as appropriate to more specialized visitors.
|
||||
#[inline(always)]
|
||||
fn visit_value(&mut self, v: Self::V) -> EvalResult<'tcx>
|
||||
{
|
||||
self.walk_value(v)
|
||||
}
|
||||
/// Visit the given value as a union. No automatic recursion can happen here.
|
||||
#[inline(always)]
|
||||
fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
/// Visit this vale as an aggregate, you are even getting an iterator yielding
|
||||
/// all the fields (still in an `EvalResult`, you have to do error handling yourself).
|
||||
/// Recurses into the fields.
|
||||
#[inline(always)]
|
||||
fn visit_aggregate(
|
||||
&mut self,
|
||||
v: Self::V,
|
||||
fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
|
||||
) -> EvalResult<'tcx> {
|
||||
self.walk_aggregate(v, fields)
|
||||
}
|
||||
/// Called each time we recurse down to a field, passing in old and new value.
|
||||
/// This gives the visitor the chance to track the stack of nested fields that
|
||||
/// we are descending through.
|
||||
#[inline(always)]
|
||||
fn visit_field(
|
||||
&mut self,
|
||||
_old_val: Self::V,
|
||||
_field: usize,
|
||||
new_val: Self::V,
|
||||
) -> EvalResult<'tcx> {
|
||||
self.visit_value(new_val)
|
||||
}
|
||||
|
||||
/// Called whenever we reach a value with uninhabited layout.
|
||||
/// Recursing to fields will *always* continue after this! This is not meant to control
|
||||
/// whether and how we descend recursively/ into the scalar's fields if there are any,
|
||||
/// it is meant to provide the chance for additional checks when a value of uninhabited
|
||||
/// layout is detected.
|
||||
#[inline(always)]
|
||||
fn visit_uninhabited(&mut self) -> EvalResult<'tcx>
|
||||
{ Ok(()) }
|
||||
/// Called whenever we reach a value with scalar layout.
|
||||
/// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
|
||||
/// visitor is not even interested in scalars.
|
||||
/// Recursing to fields will *always* continue after this! This is not meant to control
|
||||
/// whether and how we descend recursively/ into the scalar's fields if there are any,
|
||||
/// it is meant to provide the chance for additional checks when a value of scalar
|
||||
/// layout is detected.
|
||||
#[inline(always)]
|
||||
fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx>
|
||||
{ Ok(()) }
|
||||
|
||||
/// Called whenever we reach a value of primitive type. There can be no recursion
|
||||
/// below such a value. This is the leave function.
|
||||
#[inline(always)]
|
||||
fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx>
|
||||
{ Ok(()) }
|
||||
|
||||
// Default recursors. Not meant to be overloaded.
|
||||
fn walk_aggregate(
|
||||
&mut self,
|
||||
v: Self::V,
|
||||
fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
|
||||
) -> EvalResult<'tcx> {
|
||||
// Now iterate over it.
|
||||
for (idx, field_val) in fields.enumerate() {
|
||||
self.visit_field(v, idx, field_val?)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
|
||||
{
|
||||
trace!("walk_value: type: {}", v.layout().ty);
|
||||
// If this is a multi-variant layout, we have find the right one and proceed with
|
||||
// that.
|
||||
match v.layout().variants {
|
||||
layout::Variants::NicheFilling { .. } |
|
||||
layout::Variants::Tagged { .. } => {
|
||||
let op = v.to_op(self.ecx())?;
|
||||
let idx = self.ecx().read_discriminant(op)?.1;
|
||||
let inner = v.project_downcast(self.ecx(), idx)?;
|
||||
trace!("walk_value: variant layout: {:#?}", inner.layout());
|
||||
// recurse with the inner type
|
||||
return self.visit_field(v, idx, inner);
|
||||
}
|
||||
layout::Variants::Single { .. } => {}
|
||||
}
|
||||
|
||||
// Even for single variants, we might be able to get a more refined type:
|
||||
// If it is a trait object, switch to the actual type that was used to create it.
|
||||
match v.layout().ty.sty {
|
||||
ty::Dynamic(..) => {
|
||||
// immediate trait objects are not a thing
|
||||
let dest = v.to_op(self.ecx())?.to_mem_place();
|
||||
let inner = self.ecx().unpack_dyn_trait(dest)?.1;
|
||||
trace!("walk_value: dyn object layout: {:#?}", inner.layout);
|
||||
// recurse with the inner type
|
||||
return self.visit_field(v, 0, Value::from_mem_place(inner));
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
|
||||
// If this is a scalar, visit it as such.
|
||||
// Things can be aggregates and have scalar layout at the same time, and that
|
||||
// is very relevant for `NonNull` and similar structs: We need to visit them
|
||||
// at their scalar layout *before* descending into their fields.
|
||||
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
|
||||
// scalars, we do the same check on every "level" (e.g. first we check
|
||||
// MyNewtype and then the scalar in there).
|
||||
match v.layout().abi {
|
||||
layout::Abi::Uninhabited => {
|
||||
self.visit_uninhabited()?;
|
||||
}
|
||||
layout::Abi::Scalar(ref layout) => {
|
||||
self.visit_scalar(v, layout)?;
|
||||
}
|
||||
// FIXME: Should we do something for ScalarPair? Vector?
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Check primitive types. We do this after checking the scalar layout,
|
||||
// just to have that done as well. Primitives can have varying layout,
|
||||
// so we check them separately and before aggregate handling.
|
||||
// It is CRITICAL that we get this check right, or we might be
|
||||
// validating the wrong thing!
|
||||
let primitive = match v.layout().fields {
|
||||
// Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
|
||||
layout::FieldPlacement::Union(0) => true,
|
||||
_ => v.layout().ty.builtin_deref(true).is_some(),
|
||||
};
|
||||
if primitive {
|
||||
let op = v.to_op(self.ecx())?;
|
||||
let val = self.ecx().read_immediate(op)?;
|
||||
return self.visit_primitive(val);
|
||||
}
|
||||
|
||||
// Proceed into the fields.
|
||||
match v.layout().fields {
|
||||
layout::FieldPlacement::Union(fields) => {
|
||||
// Empty unions are not accepted by rustc. That's great, it means we can
|
||||
// use that as an unambiguous signal for detecting primitives. Make sure
|
||||
// we did not miss any primitive.
|
||||
debug_assert!(fields > 0);
|
||||
self.visit_union(v)?;
|
||||
},
|
||||
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
|
||||
// FIXME: We collect in a vec because otherwise there are lifetime errors:
|
||||
// Projecting to a field needs (mutable!) access to `ecx`.
|
||||
let fields: Vec<EvalResult<'tcx, Self::V>> =
|
||||
(0..offsets.len()).map(|i| {
|
||||
v.project_field(self.ecx(), i as u64)
|
||||
})
|
||||
.collect();
|
||||
self.visit_aggregate(v, fields.into_iter())?;
|
||||
},
|
||||
layout::FieldPlacement::Array { .. } => {
|
||||
// Let's get an mplace first.
|
||||
let mplace = if v.layout().is_zst() {
|
||||
// it's a ZST, the memory content cannot matter
|
||||
MPlaceTy::dangling(v.layout(), self.ecx())
|
||||
} else {
|
||||
// non-ZST array/slice/str cannot be immediate
|
||||
v.to_op(self.ecx())?.to_mem_place()
|
||||
};
|
||||
// Now we can go over all the fields.
|
||||
let iter = self.ecx().mplace_array_fields(mplace)?
|
||||
.map(|f| f.and_then(|f| {
|
||||
Ok(Value::from_mem_place(f))
|
||||
}));
|
||||
self.visit_aggregate(v, iter)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
make_value_visitor!(ValueVisitor,);
|
||||
make_value_visitor!(MutValueVisitor,mut);
|
||||
|
|
@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
|
|||
LL | | Union { u8: &BAR }.foo,
|
||||
LL | | Union { u8: &BAR }.bar,
|
||||
LL | | )};
|
||||
| |___^ type validation failed: encountered invalid enum discriminant 5 at .1.<deref>
|
||||
| |___^ type validation failed: encountered 5 at .1.<deref>, but expected a valid 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
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
|
|||
--> $DIR/transmute-const.rs:15:1
|
||||
|
|
||||
LL | static FOO: bool = unsafe { mem::transmute(3u8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected something in the range 0..=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected something less or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum Enum {
|
||||
|
|
@ -15,34 +17,48 @@ enum Enum {
|
|||
}
|
||||
union TransmuteEnum {
|
||||
a: &'static u8,
|
||||
b: Enum,
|
||||
out: Enum,
|
||||
}
|
||||
|
||||
// A pointer is guaranteed non-null
|
||||
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
|
||||
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
|
||||
//~^ ERROR is undefined behavior
|
||||
|
||||
// Invalid enum discriminant
|
||||
// (Potentially) invalid enum discriminant
|
||||
#[repr(usize)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum Enum2 {
|
||||
A = 2,
|
||||
}
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct Wrap<T>(T);
|
||||
union TransmuteEnum2 {
|
||||
a: usize,
|
||||
b: Enum2,
|
||||
in1: usize,
|
||||
in2: &'static u8,
|
||||
in3: (),
|
||||
out1: Enum2,
|
||||
out2: Wrap<Enum2>, // something wrapping the enum so that we test layout first, not enum
|
||||
}
|
||||
const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
|
||||
const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
|
||||
//~^ ERROR is undefined behavior
|
||||
const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
|
||||
//~^ ERROR is undefined behavior
|
||||
const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
|
||||
//~^ ERROR is undefined behavior
|
||||
|
||||
// Invalid enum field content (mostly to test printing of apths for enum tuple
|
||||
// Undef enum discriminant. In an arry to avoid `Scalar` layout.
|
||||
const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
|
||||
//~^ ERROR is undefined behavior
|
||||
|
||||
// Invalid enum field content (mostly to test printing of paths for enum tuple
|
||||
// variants and tuples).
|
||||
union TransmuteChar {
|
||||
a: u32,
|
||||
b: char,
|
||||
}
|
||||
// Need to create something which does not clash with enum layout optimizations.
|
||||
const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
|
||||
const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
|
||||
//~^ ERROR is undefined behavior
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,51 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-enum.rs:22:1
|
||||
--> $DIR/ub-enum.rs:24:1
|
||||
|
|
||||
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer enum discriminant
|
||||
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-enum.rs:35:1
|
||||
--> $DIR/ub-enum.rs:43:1
|
||||
|
|
||||
LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant 0
|
||||
LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-enum.rs:45:1
|
||||
|
|
||||
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
|
||||
LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid 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
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-enum.rs:47:1
|
||||
|
|
||||
LL | const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-enum.rs:51:1
|
||||
|
|
||||
LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-enum.rs:61:1
|
||||
|
|
||||
LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something less or equal to 1114111
|
||||
|
|
||||
= 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
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(const_transmute)]
|
||||
#![feature(rustc_attrs, const_transmute)]
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
use std::mem;
|
||||
use std::ptr::NonNull;
|
||||
|
|
@ -22,4 +23,18 @@ const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
|
|||
const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
|
||||
// Also test other uses of rustc_layout_scalar_valid_range_start
|
||||
|
||||
#[rustc_layout_scalar_valid_range_start(10)]
|
||||
#[rustc_layout_scalar_valid_range_end(30)]
|
||||
struct RestrictedRange1(u32);
|
||||
const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
|
||||
#[rustc_layout_scalar_valid_range_start(30)]
|
||||
#[rustc_layout_scalar_valid_range_end(10)]
|
||||
struct RestrictedRange2(u32);
|
||||
const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:17:1
|
||||
--> $DIR/ub-nonnull.rs:18:1
|
||||
|
|
||||
LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
|
||||
|
|
@ -7,7 +7,7 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:20:1
|
||||
--> $DIR/ub-nonnull.rs:21:1
|
||||
|
|
||||
LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
|
||||
|
|
@ -15,13 +15,29 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:22:1
|
||||
--> $DIR/ub-nonnull.rs:23:1
|
||||
|
|
||||
LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:31:1
|
||||
|
|
||||
LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:37:1
|
||||
|
|
||||
LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30
|
||||
|
|
||||
= 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
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![feature(const_transmute)]
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-ref.rs:15:1
|
||||
--> $DIR/ub-ref.rs:16:1
|
||||
|
|
||||
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference
|
||||
|
|
@ -7,7 +7,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-ref.rs:18:1
|
||||
--> $DIR/ub-ref.rs:19:1
|
||||
|
|
||||
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
|
||||
|
|
@ -15,7 +15,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-ref.rs:21:1
|
||||
--> $DIR/ub-ref.rs:22:1
|
||||
|
|
||||
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
||||
|
|
@ -23,15 +23,15 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-ref.rs:24:1
|
||||
--> $DIR/ub-ref.rs:25:1
|
||||
|
|
||||
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain bytes
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-ref.rs:27:1
|
||||
--> $DIR/ub-ref.rs:28:1
|
||||
|
|
||||
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![feature(const_transmute)]
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-uninhabit.rs:18:1
|
||||
--> $DIR/ub-uninhabit.rs:19:1
|
||||
|
|
||||
LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
|
||||
|
|
@ -7,7 +7,7 @@ LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-uninhabit.rs:21:1
|
||||
--> $DIR/ub-uninhabit.rs:22:1
|
||||
|
|
||||
LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
|
||||
|
|
@ -15,7 +15,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-uninhabit.rs:24:1
|
||||
--> $DIR/ub-uninhabit.rs:25:1
|
||||
|
|
||||
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at [0]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![feature(const_transmute,const_let)]
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-upvars.rs:15:1
|
||||
--> $DIR/ub-upvars.rs:16:1
|
||||
|
|
||||
LL | / const BAD_UPVAR: &FnOnce() = &{ //~ ERROR it is undefined behavior to use this value
|
||||
LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
|
||||
LL | | let another_var = 13;
|
||||
LL | | move || { let _ = bad_ref; let _ = another_var; }
|
||||
LL | | };
|
||||
| |__^ type validation failed: encountered 0 at .<deref>.<closure-var(bad_ref)>, but expected something greater or equal to 1
|
||||
| |__^ type validation failed: encountered 0 at .<deref>.<dyn-downcast>.<closure-var(bad_ref)>, but expected something greater or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![allow(unused)]
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
// normalize-stderr-test "alignment \d+" -> "alignment N"
|
||||
// normalize-stderr-test "offset \d+" -> "offset N"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:87:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:88:1
|
||||
|
|
||||
LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
|
||||
|
|
@ -7,7 +7,7 @@ LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len:
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:90:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:91:1
|
||||
|
|
||||
LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
|
||||
|
|
@ -15,7 +15,7 @@ LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:93:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:94:1
|
||||
|
|
||||
LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
|
||||
|
|
@ -23,7 +23,7 @@ LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42,
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:99:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:100:1
|
||||
|
|
||||
LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
|
||||
|
|
@ -31,7 +31,7 @@ LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:102:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:103:1
|
||||
|
|
||||
LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
|
||||
|
|
@ -39,7 +39,7 @@ LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, l
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:106:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:107:1
|
||||
|
|
||||
LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
|
||||
|
|
@ -47,7 +47,7 @@ LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable:
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:109:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:110:1
|
||||
|
|
||||
LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
|
||||
|
|
@ -55,7 +55,7 @@ LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtabl
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:112:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:113:1
|
||||
|
|
||||
LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
|
||||
|
|
@ -63,39 +63,39 @@ LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtabl
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:116:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:117:1
|
||||
|
|
||||
LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.<dyn-downcast>, but expected something less or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:120:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:121:1
|
||||
|
|
||||
LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something less or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:126:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:127:1
|
||||
|
|
||||
LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something less or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:129:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:130:1
|
||||
|
|
||||
LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something less or equal to 1
|
||||
|
|
||||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:133:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:134:1
|
||||
|
|
||||
LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
|
||||
|
|
@ -103,7 +103,7 @@ LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
|
|||
= 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
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub-fat-ptr.rs:136:1
|
||||
--> $DIR/union-ub-fat-ptr.rs:137:1
|
||||
|
|
||||
LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
union DummyUnion {
|
||||
u8: u8,
|
||||
bool: bool,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/union-ub.rs:36:1
|
||||
--> $DIR/union-ub.rs:38:1
|
||||
|
|
||||
LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 0..=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something less or equal to 1
|
||||
|
|
||||
= 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…
Add table
Add a link
Reference in a new issue