Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4e86576

Browse files
committedNov 7, 2018
Rollup merge of #55645 - RalfJung:validity-range-inclusive, r=oli-obk
do not print wrapping ranges like normal ranges in validity diagnostics
2 parents 9d9146a + 3ec8974 commit 4e86576

27 files changed

+898
-483
lines changed
 

‎src/librustc/mir/interpret/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use ty::{Ty, layout};
1515
use ty::layout::{Size, Align, LayoutError};
1616
use rustc_target::spec::abi::Abi;
1717

18-
use super::Pointer;
18+
use super::{Pointer, Scalar};
1919

2020
use backtrace::Backtrace;
2121

@@ -240,7 +240,7 @@ pub enum EvalErrorKind<'tcx, O> {
240240
InvalidMemoryAccess,
241241
InvalidFunctionPointer,
242242
InvalidBool,
243-
InvalidDiscriminant(u128),
243+
InvalidDiscriminant(Scalar),
244244
PointerOutOfBounds {
245245
ptr: Pointer,
246246
access: bool,

‎src/librustc/mir/interpret/mod.rs

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -91,42 +91,43 @@ pub trait PointerArithmetic: layout::HasDataLayout {
9191
}
9292

9393
//// Trunace the given value to the pointer size; also return whether there was an overflow
94+
#[inline]
9495
fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
9596
let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
9697
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
9798
}
9899

99-
// Overflow checking only works properly on the range from -u64 to +u64.
100-
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
101-
// FIXME: is it possible to over/underflow here?
102-
if i < 0 {
103-
// trickery to ensure that i64::min_value() works fine
104-
// this formula only works for true negative values, it panics for zero!
105-
let n = u64::max_value() - (i as u64) + 1;
106-
val.overflowing_sub(n)
107-
} else {
108-
self.overflowing_offset(val, i as u64)
109-
}
100+
#[inline]
101+
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
102+
let (res, over) = self.overflowing_offset(val, i);
103+
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
110104
}
111105

106+
#[inline]
112107
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
113108
let (res, over1) = val.overflowing_add(i);
114-
let (res, over2) = self.truncate_to_ptr(res as u128);
109+
let (res, over2) = self.truncate_to_ptr(u128::from(res));
115110
(res, over1 || over2)
116111
}
117112

113+
#[inline]
118114
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
119-
let (res, over) = self.overflowing_signed_offset(val, i as i128);
115+
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
120116
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
121117
}
122118

123-
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
124-
let (res, over) = self.overflowing_offset(val, i);
125-
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
126-
}
127-
128-
fn wrapping_signed_offset(&self, val: u64, i: i64) -> u64 {
129-
self.overflowing_signed_offset(val, i as i128).0
119+
// Overflow checking only works properly on the range from -u64 to +u64.
120+
#[inline]
121+
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
122+
// FIXME: is it possible to over/underflow here?
123+
if i < 0 {
124+
// trickery to ensure that i64::min_value() works fine
125+
// this formula only works for true negative values, it panics for zero!
126+
let n = u64::max_value() - (i as u64) + 1;
127+
val.overflowing_sub(n)
128+
} else {
129+
self.overflowing_offset(val, i as u64)
130+
}
130131
}
131132
}
132133

@@ -176,19 +177,27 @@ impl<'tcx, Tag> Pointer<Tag> {
176177
Pointer { alloc_id, offset, tag }
177178
}
178179

179-
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
180-
Pointer::new_with_tag(
180+
#[inline]
181+
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
182+
Ok(Pointer::new_with_tag(
181183
self.alloc_id,
182-
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
183-
self.tag,
184-
)
184+
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
185+
self.tag
186+
))
185187
}
186188

187-
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
188-
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
189+
#[inline]
190+
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
191+
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
189192
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
190193
}
191194

195+
#[inline(always)]
196+
pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
197+
self.overflowing_offset(i, cx).0
198+
}
199+
200+
#[inline]
192201
pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
193202
Ok(Pointer::new_with_tag(
194203
self.alloc_id,
@@ -197,20 +206,18 @@ impl<'tcx, Tag> Pointer<Tag> {
197206
))
198207
}
199208

200-
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
201-
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
209+
#[inline]
210+
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
211+
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
202212
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
203213
}
204214

205-
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
206-
Ok(Pointer::new_with_tag(
207-
self.alloc_id,
208-
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
209-
self.tag
210-
))
215+
#[inline(always)]
216+
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
217+
self.overflowing_signed_offset(i128::from(i), cx).0
211218
}
212219

213-
#[inline]
220+
#[inline(always)]
214221
pub fn erase_tag(self) -> Pointer {
215222
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
216223
}

‎src/librustc/mir/interpret/value.rs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![allow(unknown_lints)]
11+
use std::fmt;
1212

1313
use ty::layout::{HasDataLayout, Size};
1414
use ty::subst::Substs;
@@ -99,6 +99,15 @@ pub enum Scalar<Tag=(), Id=AllocId> {
9999
Ptr(Pointer<Tag, Id>),
100100
}
101101

102+
impl<Tag> fmt::Display for Scalar<Tag> {
103+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104+
match self {
105+
Scalar::Ptr(_) => write!(f, "a pointer"),
106+
Scalar::Bits { bits, .. } => write!(f, "{}", bits),
107+
}
108+
}
109+
}
110+
102111
impl<'tcx> Scalar<()> {
103112
#[inline]
104113
pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
@@ -134,32 +143,47 @@ impl<'tcx, Tag> Scalar<Tag> {
134143
}
135144

136145
#[inline]
137-
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
146+
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
138147
let dl = cx.data_layout();
139148
match self {
140149
Scalar::Bits { bits, size } => {
141150
assert_eq!(size as u64, dl.pointer_size.bytes());
142151
Ok(Scalar::Bits {
143-
bits: dl.signed_offset(bits as u64, i)? as u128,
152+
bits: dl.offset(bits as u64, i.bytes())? as u128,
144153
size,
145154
})
146155
}
147-
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
156+
Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr),
148157
}
149158
}
150159

151160
#[inline]
152-
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
161+
pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
153162
let dl = cx.data_layout();
154163
match self {
155164
Scalar::Bits { bits, size } => {
156165
assert_eq!(size as u64, dl.pointer_size.bytes());
166+
Scalar::Bits {
167+
bits: dl.overflowing_offset(bits as u64, i.bytes()).0 as u128,
168+
size,
169+
}
170+
}
171+
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_offset(i, dl)),
172+
}
173+
}
174+
175+
#[inline]
176+
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
177+
let dl = cx.data_layout();
178+
match self {
179+
Scalar::Bits { bits, size } => {
180+
assert_eq!(size as u64, dl.pointer_size().bytes());
157181
Ok(Scalar::Bits {
158-
bits: dl.offset(bits as u64, i.bytes())? as u128,
182+
bits: dl.signed_offset(bits as u64, i)? as u128,
159183
size,
160184
})
161185
}
162-
Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr),
186+
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
163187
}
164188
}
165189

@@ -170,14 +194,27 @@ impl<'tcx, Tag> Scalar<Tag> {
170194
Scalar::Bits { bits, size } => {
171195
assert_eq!(size as u64, dl.pointer_size.bytes());
172196
Scalar::Bits {
173-
bits: dl.wrapping_signed_offset(bits as u64, i) as u128,
197+
bits: dl.overflowing_signed_offset(bits as u64, i128::from(i)).0 as u128,
174198
size,
175199
}
176200
}
177201
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, dl)),
178202
}
179203
}
180204

205+
/// Returns this pointers offset from the allocation base, or from NULL (for
206+
/// integer pointers).
207+
#[inline]
208+
pub fn get_ptr_offset(self, cx: &impl HasDataLayout) -> Size {
209+
match self {
210+
Scalar::Bits { bits, size } => {
211+
assert_eq!(size as u64, cx.pointer_size().bytes());
212+
Size::from_bytes(bits as u64)
213+
}
214+
Scalar::Ptr(ptr) => ptr.offset,
215+
}
216+
}
217+
181218
#[inline]
182219
pub fn is_null_ptr(self, cx: &impl HasDataLayout) -> bool {
183220
match self {

‎src/librustc_mir/const_eval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,10 +539,10 @@ fn validate_const<'a, 'tcx>(
539539
let val = (|| {
540540
let op = ecx.const_to_op(constant)?;
541541
let mut ref_tracking = RefTracking::new(op);
542-
while let Some((op, mut path)) = ref_tracking.todo.pop() {
542+
while let Some((op, path)) = ref_tracking.todo.pop() {
543543
ecx.validate_operand(
544544
op,
545-
&mut path,
545+
path,
546546
Some(&mut ref_tracking),
547547
/* const_mode */ true,
548548
)?;

‎src/librustc_mir/interpret/eval_context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
521521
// return place is always a local and then this cannot happen.
522522
self.validate_operand(
523523
self.place_to_op(return_place)?,
524-
&mut vec![],
524+
vec![],
525525
None,
526526
/*const_mode*/false,
527527
)?;

‎src/librustc_mir/interpret/machine.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use std::hash::Hash;
1717

1818
use rustc::hir::{self, def_id::DefId};
1919
use rustc::mir;
20-
use rustc::ty::{self, Ty, layout::{Size, TyLayout}, query::TyCtxtAt};
20+
use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt};
2121

2222
use super::{
2323
Allocation, AllocId, EvalResult, Scalar,
24-
EvalContext, PlaceTy, OpTy, Pointer, MemPlace, MemoryKind,
24+
EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
2525
};
2626

2727
/// Whether this kind of memory is allowed to leak
@@ -217,26 +217,22 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
217217
#[inline]
218218
fn tag_reference(
219219
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
220-
place: MemPlace<Self::PointerTag>,
221-
_ty: Ty<'tcx>,
222-
_size: Size,
220+
place: MPlaceTy<'tcx, Self::PointerTag>,
223221
_mutability: Option<hir::Mutability>,
224-
) -> EvalResult<'tcx, MemPlace<Self::PointerTag>> {
225-
Ok(place)
222+
) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
223+
Ok(place.ptr)
226224
}
227225

228226
/// Executed when evaluating the `*` operator: Following a reference.
229-
/// This has the change to adjust the tag. It should not change anything else!
227+
/// This has the chance to adjust the tag. It should not change anything else!
230228
/// `mutability` can be `None` in case a raw ptr is being dereferenced.
231229
#[inline]
232230
fn tag_dereference(
233231
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
234-
place: MemPlace<Self::PointerTag>,
235-
_ty: Ty<'tcx>,
236-
_size: Size,
232+
place: MPlaceTy<'tcx, Self::PointerTag>,
237233
_mutability: Option<hir::Mutability>,
238-
) -> EvalResult<'tcx, MemPlace<Self::PointerTag>> {
239-
Ok(place)
234+
) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
235+
Ok(place.ptr)
240236
}
241237

242238
/// Execute a validation operation

‎src/librustc_mir/interpret/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod terminator;
2323
mod traits;
2424
mod validity;
2525
mod intrinsics;
26+
mod visitor;
2627

2728
pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
2829

@@ -38,4 +39,6 @@ pub use self::machine::{Machine, AllocMap, MayLeak};
3839

3940
pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy};
4041

42+
pub use self::visitor::ValueVisitor;
43+
4144
pub use self::validity::RefTracking;

‎src/librustc_mir/interpret/operand.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! All high-level functions to read from memory work on operands as sources.
1313
1414
use std::convert::TryInto;
15+
use std::fmt;
1516

1617
use rustc::{mir, ty};
1718
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
@@ -36,6 +37,15 @@ impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
3637
}
3738
}
3839

40+
impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
41+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42+
match self {
43+
ScalarMaybeUndef::Undef => write!(f, "uninitialized bytes"),
44+
ScalarMaybeUndef::Scalar(s) => write!(f, "{}", s),
45+
}
46+
}
47+
}
48+
3949
impl<'tcx> ScalarMaybeUndef<()> {
4050
#[inline]
4151
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>
732742
Ok(match rval.layout.variants {
733743
layout::Variants::Single { .. } => bug!(),
734744
layout::Variants::Tagged { .. } => {
745+
let bits_discr = match raw_discr.to_bits(discr_val.layout.size) {
746+
Ok(raw_discr) => raw_discr,
747+
Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())),
748+
};
735749
let real_discr = if discr_val.layout.ty.is_signed() {
736-
let i = raw_discr.to_bits(discr_val.layout.size)? as i128;
750+
let i = bits_discr as i128;
737751
// going from layout tag type to typeck discriminant type
738752
// requires first sign extending with the layout discriminant
739753
let shift = 128 - discr_val.layout.size.bits();
@@ -748,15 +762,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
748762
let truncatee = sexted as u128;
749763
(truncatee << shift) >> shift
750764
} else {
751-
raw_discr.to_bits(discr_val.layout.size)?
765+
bits_discr
752766
};
753767
// Make sure we catch invalid discriminants
754768
let index = rval.layout.ty
755769
.ty_adt_def()
756770
.expect("tagged layout for non adt")
757771
.discriminants(self.tcx.tcx)
758772
.position(|var| var.val == real_discr)
759-
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(real_discr))?;
773+
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?;
760774
(real_discr, index)
761775
},
762776
layout::Variants::NicheFilling {

‎src/librustc_mir/interpret/place.rs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -278,42 +278,34 @@ where
278278
let meta = val.to_meta()?;
279279
let ptr = val.to_scalar_ptr()?;
280280
let mplace = MemPlace { ptr, align, meta };
281+
let mut mplace = MPlaceTy { mplace, layout };
281282
// Pointer tag tracking might want to adjust the tag.
282-
let mplace = if M::ENABLE_PTR_TRACKING_HOOKS {
283-
let (size, _) = self.size_and_align_of(meta, layout)?
284-
// for extern types, just cover what we can
285-
.unwrap_or_else(|| layout.size_and_align());
283+
if M::ENABLE_PTR_TRACKING_HOOKS {
286284
let mutbl = match val.layout.ty.sty {
287285
// `builtin_deref` considers boxes immutable, that's useless for our purposes
288286
ty::Ref(_, _, mutbl) => Some(mutbl),
289287
ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable),
290288
ty::RawPtr(_) => None,
291289
_ => bug!("Unexpected pointer type {}", val.layout.ty.sty),
292290
};
293-
M::tag_dereference(self, mplace, pointee_type, size, mutbl)?
294-
} else {
295-
mplace
296-
};
297-
Ok(MPlaceTy { mplace, layout })
291+
mplace.mplace.ptr = M::tag_dereference(self, mplace, mutbl)?;
292+
}
293+
// Done
294+
Ok(mplace)
298295
}
299296

300297
/// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
301298
/// This is the inverse of `ref_to_mplace`.
302299
/// `mutbl` indicates whether we are create a shared or mutable ref, or a raw pointer (`None`).
303300
pub fn create_ref(
304301
&mut self,
305-
place: MPlaceTy<'tcx, M::PointerTag>,
302+
mut place: MPlaceTy<'tcx, M::PointerTag>,
306303
mutbl: Option<hir::Mutability>,
307304
) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
308305
// Pointer tag tracking might want to adjust the tag
309-
let place = if M::ENABLE_PTR_TRACKING_HOOKS {
310-
let (size, _) = self.size_and_align_of_mplace(place)?
311-
// for extern types, just cover what we can
312-
.unwrap_or_else(|| place.layout.size_and_align());
313-
M::tag_reference(self, *place, place.layout.ty, size, mutbl)?
314-
} else {
315-
*place
316-
};
306+
if M::ENABLE_PTR_TRACKING_HOOKS {
307+
place.mplace.ptr = M::tag_reference(self, place, mutbl)?
308+
}
317309
Ok(match place.meta {
318310
None => Immediate::Scalar(place.ptr.into()),
319311
Some(meta) => Immediate::ScalarPair(place.ptr.into(), meta.into()),
@@ -489,6 +481,8 @@ where
489481

490482
/// Get the place of a field inside the place, and also the field's type.
491483
/// Just a convenience function, but used quite a bit.
484+
/// This is the only projection that might have a side-effect: We cannot project
485+
/// into the field of a local `ScalarPair`, we have to first allocate it.
492486
pub fn place_field(
493487
&mut self,
494488
base: PlaceTy<'tcx, M::PointerTag>,
@@ -501,7 +495,7 @@ where
501495
}
502496

503497
pub fn place_downcast(
504-
&mut self,
498+
&self,
505499
base: PlaceTy<'tcx, M::PointerTag>,
506500
variant: usize,
507501
) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
@@ -643,7 +637,7 @@ where
643637

644638
if M::enforce_validity(self) {
645639
// Data got changed, better make sure it matches the type!
646-
self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
640+
self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
647641
}
648642

649643
Ok(())
@@ -765,7 +759,7 @@ where
765759

766760
if M::enforce_validity(self) {
767761
// Data got changed, better make sure it matches the type!
768-
self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
762+
self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
769763
}
770764

771765
Ok(())
@@ -843,7 +837,7 @@ where
843837

844838
if M::enforce_validity(self) {
845839
// Data got changed, better make sure it matches the type!
846-
self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
840+
self.validate_operand(dest.into(), vec![], None, /*const_mode*/false)?;
847841
}
848842

849843
Ok(())

‎src/librustc_mir/interpret/validity.rs

Lines changed: 308 additions & 341 deletions
Large diffs are not rendered by default.

‎src/librustc_mir/interpret/visitor.rs

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
2+
//! types until we arrive at the leaves, with custom handling for primitive types.
3+
4+
use rustc::ty::layout::{self, TyLayout};
5+
use rustc::ty;
6+
use rustc::mir::interpret::{
7+
EvalResult,
8+
};
9+
10+
use super::{
11+
Machine, EvalContext, MPlaceTy, OpTy, ImmTy,
12+
};
13+
14+
// A thing that we can project into, and that has a layout.
15+
// This wouldn't have to depend on `Machine` but with the current type inference,
16+
// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
17+
pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
18+
{
19+
/// Get this value's layout.
20+
fn layout(&self) -> TyLayout<'tcx>;
21+
22+
/// Make this into an `OpTy`.
23+
fn to_op(
24+
self,
25+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
26+
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>;
27+
28+
/// Create this from an `MPlaceTy`.
29+
fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;
30+
31+
/// Project to the given enum variant.
32+
fn project_downcast(
33+
self,
34+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
35+
variant: usize,
36+
) -> EvalResult<'tcx, Self>;
37+
38+
/// Project to the n-th field.
39+
fn project_field(
40+
self,
41+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
42+
field: u64,
43+
) -> EvalResult<'tcx, Self>;
44+
}
45+
46+
// Operands and memory-places are both values.
47+
// Places in general are not due to `place_field` having to do `force_allocation`.
48+
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
49+
for OpTy<'tcx, M::PointerTag>
50+
{
51+
#[inline(always)]
52+
fn layout(&self) -> TyLayout<'tcx> {
53+
self.layout
54+
}
55+
56+
#[inline(always)]
57+
fn to_op(
58+
self,
59+
_ecx: &EvalContext<'a, 'mir, 'tcx, M>,
60+
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
61+
Ok(self)
62+
}
63+
64+
#[inline(always)]
65+
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
66+
mplace.into()
67+
}
68+
69+
#[inline(always)]
70+
fn project_downcast(
71+
self,
72+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
73+
variant: usize,
74+
) -> EvalResult<'tcx, Self> {
75+
ecx.operand_downcast(self, variant)
76+
}
77+
78+
#[inline(always)]
79+
fn project_field(
80+
self,
81+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
82+
field: u64,
83+
) -> EvalResult<'tcx, Self> {
84+
ecx.operand_field(self, field)
85+
}
86+
}
87+
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
88+
for MPlaceTy<'tcx, M::PointerTag>
89+
{
90+
#[inline(always)]
91+
fn layout(&self) -> TyLayout<'tcx> {
92+
self.layout
93+
}
94+
95+
#[inline(always)]
96+
fn to_op(
97+
self,
98+
_ecx: &EvalContext<'a, 'mir, 'tcx, M>,
99+
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
100+
Ok(self.into())
101+
}
102+
103+
#[inline(always)]
104+
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
105+
mplace
106+
}
107+
108+
#[inline(always)]
109+
fn project_downcast(
110+
self,
111+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
112+
variant: usize,
113+
) -> EvalResult<'tcx, Self> {
114+
ecx.mplace_downcast(self, variant)
115+
}
116+
117+
#[inline(always)]
118+
fn project_field(
119+
self,
120+
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
121+
field: u64,
122+
) -> EvalResult<'tcx, Self> {
123+
ecx.mplace_field(self, field)
124+
}
125+
}
126+
127+
macro_rules! make_value_visitor {
128+
($visitor_trait_name:ident, $($mutability:ident)*) => {
129+
// How to traverse a value and what to do when we are at the leaves.
130+
pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
131+
type V: Value<'a, 'mir, 'tcx, M>;
132+
133+
/// The visitor must have an `EvalContext` in it.
134+
fn ecx(&$($mutability)* self)
135+
-> &$($mutability)* EvalContext<'a, 'mir, 'tcx, M>;
136+
137+
// Recursive actions, ready to be overloaded.
138+
/// Visit the given value, dispatching as appropriate to more specialized visitors.
139+
#[inline(always)]
140+
fn visit_value(&mut self, v: Self::V) -> EvalResult<'tcx>
141+
{
142+
self.walk_value(v)
143+
}
144+
/// Visit the given value as a union. No automatic recursion can happen here.
145+
#[inline(always)]
146+
fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx>
147+
{
148+
Ok(())
149+
}
150+
/// Visit this vale as an aggregate, you are even getting an iterator yielding
151+
/// all the fields (still in an `EvalResult`, you have to do error handling yourself).
152+
/// Recurses into the fields.
153+
#[inline(always)]
154+
fn visit_aggregate(
155+
&mut self,
156+
v: Self::V,
157+
fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
158+
) -> EvalResult<'tcx> {
159+
self.walk_aggregate(v, fields)
160+
}
161+
/// Called each time we recurse down to a field, passing in old and new value.
162+
/// This gives the visitor the chance to track the stack of nested fields that
163+
/// we are descending through.
164+
#[inline(always)]
165+
fn visit_field(
166+
&mut self,
167+
_old_val: Self::V,
168+
_field: usize,
169+
new_val: Self::V,
170+
) -> EvalResult<'tcx> {
171+
self.visit_value(new_val)
172+
}
173+
174+
/// Called whenever we reach a value with uninhabited layout.
175+
/// Recursing to fields will *always* continue after this! This is not meant to control
176+
/// whether and how we descend recursively/ into the scalar's fields if there are any,
177+
/// it is meant to provide the chance for additional checks when a value of uninhabited
178+
/// layout is detected.
179+
#[inline(always)]
180+
fn visit_uninhabited(&mut self) -> EvalResult<'tcx>
181+
{ Ok(()) }
182+
/// Called whenever we reach a value with scalar layout.
183+
/// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
184+
/// visitor is not even interested in scalars.
185+
/// Recursing to fields will *always* continue after this! This is not meant to control
186+
/// whether and how we descend recursively/ into the scalar's fields if there are any,
187+
/// it is meant to provide the chance for additional checks when a value of scalar
188+
/// layout is detected.
189+
#[inline(always)]
190+
fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx>
191+
{ Ok(()) }
192+
193+
/// Called whenever we reach a value of primitive type. There can be no recursion
194+
/// below such a value. This is the leave function.
195+
#[inline(always)]
196+
fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx>
197+
{ Ok(()) }
198+
199+
// Default recursors. Not meant to be overloaded.
200+
fn walk_aggregate(
201+
&mut self,
202+
v: Self::V,
203+
fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
204+
) -> EvalResult<'tcx> {
205+
// Now iterate over it.
206+
for (idx, field_val) in fields.enumerate() {
207+
self.visit_field(v, idx, field_val?)?;
208+
}
209+
Ok(())
210+
}
211+
fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
212+
{
213+
trace!("walk_value: type: {}", v.layout().ty);
214+
// If this is a multi-variant layout, we have find the right one and proceed with
215+
// that.
216+
match v.layout().variants {
217+
layout::Variants::NicheFilling { .. } |
218+
layout::Variants::Tagged { .. } => {
219+
let op = v.to_op(self.ecx())?;
220+
let idx = self.ecx().read_discriminant(op)?.1;
221+
let inner = v.project_downcast(self.ecx(), idx)?;
222+
trace!("walk_value: variant layout: {:#?}", inner.layout());
223+
// recurse with the inner type
224+
return self.visit_field(v, idx, inner);
225+
}
226+
layout::Variants::Single { .. } => {}
227+
}
228+
229+
// Even for single variants, we might be able to get a more refined type:
230+
// If it is a trait object, switch to the actual type that was used to create it.
231+
match v.layout().ty.sty {
232+
ty::Dynamic(..) => {
233+
// immediate trait objects are not a thing
234+
let dest = v.to_op(self.ecx())?.to_mem_place();
235+
let inner = self.ecx().unpack_dyn_trait(dest)?.1;
236+
trace!("walk_value: dyn object layout: {:#?}", inner.layout);
237+
// recurse with the inner type
238+
return self.visit_field(v, 0, Value::from_mem_place(inner));
239+
},
240+
_ => {},
241+
};
242+
243+
// If this is a scalar, visit it as such.
244+
// Things can be aggregates and have scalar layout at the same time, and that
245+
// is very relevant for `NonNull` and similar structs: We need to visit them
246+
// at their scalar layout *before* descending into their fields.
247+
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
248+
// scalars, we do the same check on every "level" (e.g. first we check
249+
// MyNewtype and then the scalar in there).
250+
match v.layout().abi {
251+
layout::Abi::Uninhabited => {
252+
self.visit_uninhabited()?;
253+
}
254+
layout::Abi::Scalar(ref layout) => {
255+
self.visit_scalar(v, layout)?;
256+
}
257+
// FIXME: Should we do something for ScalarPair? Vector?
258+
_ => {}
259+
}
260+
261+
// Check primitive types. We do this after checking the scalar layout,
262+
// just to have that done as well. Primitives can have varying layout,
263+
// so we check them separately and before aggregate handling.
264+
// It is CRITICAL that we get this check right, or we might be
265+
// validating the wrong thing!
266+
let primitive = match v.layout().fields {
267+
// Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
268+
layout::FieldPlacement::Union(0) => true,
269+
_ => v.layout().ty.builtin_deref(true).is_some(),
270+
};
271+
if primitive {
272+
let op = v.to_op(self.ecx())?;
273+
let val = self.ecx().read_immediate(op)?;
274+
return self.visit_primitive(val);
275+
}
276+
277+
// Proceed into the fields.
278+
match v.layout().fields {
279+
layout::FieldPlacement::Union(fields) => {
280+
// Empty unions are not accepted by rustc. That's great, it means we can
281+
// use that as an unambiguous signal for detecting primitives. Make sure
282+
// we did not miss any primitive.
283+
debug_assert!(fields > 0);
284+
self.visit_union(v)?;
285+
},
286+
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
287+
// FIXME: We collect in a vec because otherwise there are lifetime errors:
288+
// Projecting to a field needs (mutable!) access to `ecx`.
289+
let fields: Vec<EvalResult<'tcx, Self::V>> =
290+
(0..offsets.len()).map(|i| {
291+
v.project_field(self.ecx(), i as u64)
292+
})
293+
.collect();
294+
self.visit_aggregate(v, fields.into_iter())?;
295+
},
296+
layout::FieldPlacement::Array { .. } => {
297+
// Let's get an mplace first.
298+
let mplace = if v.layout().is_zst() {
299+
// it's a ZST, the memory content cannot matter
300+
MPlaceTy::dangling(v.layout(), self.ecx())
301+
} else {
302+
// non-ZST array/slice/str cannot be immediate
303+
v.to_op(self.ecx())?.to_mem_place()
304+
};
305+
// Now we can go over all the fields.
306+
let iter = self.ecx().mplace_array_fields(mplace)?
307+
.map(|f| f.and_then(|f| {
308+
Ok(Value::from_mem_place(f))
309+
}));
310+
self.visit_aggregate(v, iter)?;
311+
}
312+
}
313+
Ok(())
314+
}
315+
}
316+
}
317+
}
318+
319+
make_value_visitor!(ValueVisitor,);
320+
make_value_visitor!(MutValueVisitor,mut);

‎src/test/ui/consts/const-eval/double_check2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
55
LL | | Union { u8: &BAR }.foo,
66
LL | | Union { u8: &BAR }.bar,
77
LL | | )};
8-
| |___^ type validation failed: encountered invalid enum discriminant 5 at .1.<deref>
8+
| |___^ type validation failed: encountered 5 at .1.<deref>, but expected a valid enum discriminant
99
|
1010
= 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
1111

‎src/test/ui/consts/const-eval/transmute-const.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/transmute-const.rs:15:1
33
|
44
LL | static FOO: bool = unsafe { mem::transmute(3u8) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected something in the range 0..=1
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected something less or equal to 1
66
|
77
= 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
88

‎src/test/ui/consts/const-eval/ub-enum.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,57 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
12+
1113
#[repr(usize)]
1214
#[derive(Copy, Clone)]
1315
enum Enum {
1416
A = 0,
1517
}
1618
union TransmuteEnum {
1719
a: &'static u8,
18-
b: Enum,
20+
out: Enum,
1921
}
2022

2123
// A pointer is guaranteed non-null
22-
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
24+
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
2325
//~^ ERROR is undefined behavior
2426

25-
// Invalid enum discriminant
27+
// (Potentially) invalid enum discriminant
2628
#[repr(usize)]
2729
#[derive(Copy, Clone)]
2830
enum Enum2 {
2931
A = 2,
3032
}
33+
#[repr(transparent)]
34+
#[derive(Copy, Clone)]
35+
struct Wrap<T>(T);
3136
union TransmuteEnum2 {
32-
a: usize,
33-
b: Enum2,
37+
in1: usize,
38+
in2: &'static u8,
39+
in3: (),
40+
out1: Enum2,
41+
out2: Wrap<Enum2>, // something wrapping the enum so that we test layout first, not enum
3442
}
35-
const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
43+
const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
44+
//~^ ERROR is undefined behavior
45+
const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
46+
//~^ ERROR is undefined behavior
47+
const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
48+
//~^ ERROR is undefined behavior
49+
50+
// Undef enum discriminant. In an arry to avoid `Scalar` layout.
51+
const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
3652
//~^ ERROR is undefined behavior
3753

38-
// Invalid enum field content (mostly to test printing of apths for enum tuple
54+
// Invalid enum field content (mostly to test printing of paths for enum tuple
3955
// variants and tuples).
4056
union TransmuteChar {
4157
a: u32,
4258
b: char,
4359
}
4460
// Need to create something which does not clash with enum layout optimizations.
45-
const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
61+
const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
4662
//~^ ERROR is undefined behavior
4763

4864
fn main() {
Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-enum.rs:22:1
2+
--> $DIR/ub-enum.rs:24:1
33
|
4-
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer enum discriminant
4+
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
66
|
77
= 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
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-enum.rs:35:1
10+
--> $DIR/ub-enum.rs:43:1
1111
|
12-
LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant 0
12+
LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant
1414
|
1515
= 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
1616

1717
error[E0080]: it is undefined behavior to use this value
1818
--> $DIR/ub-enum.rs:45:1
1919
|
20-
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
21-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
20+
LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
2222
|
2323
= 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
2424

25-
error: aborting due to 3 previous errors
25+
error[E0080]: it is undefined behavior to use this value
26+
--> $DIR/ub-enum.rs:47:1
27+
|
28+
LL | const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2
30+
|
31+
= 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
32+
33+
error[E0080]: it is undefined behavior to use this value
34+
--> $DIR/ub-enum.rs:51:1
35+
|
36+
LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
38+
|
39+
= 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
40+
41+
error[E0080]: it is undefined behavior to use this value
42+
--> $DIR/ub-enum.rs:61:1
43+
|
44+
LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something less or equal to 1114111
46+
|
47+
= 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
48+
49+
error: aborting due to 6 previous errors
2650

2751
For more information about this error, try `rustc --explain E0080`.

‎src/test/ui/consts/const-eval/ub-nonnull.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(const_transmute)]
11+
#![feature(rustc_attrs, const_transmute)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
use std::mem;
1415
use std::ptr::NonNull;
@@ -22,4 +23,18 @@ const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
2223
const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
2324
//~^ ERROR it is undefined behavior to use this value
2425

26+
// Also test other uses of rustc_layout_scalar_valid_range_start
27+
28+
#[rustc_layout_scalar_valid_range_start(10)]
29+
#[rustc_layout_scalar_valid_range_end(30)]
30+
struct RestrictedRange1(u32);
31+
const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
32+
//~^ ERROR it is undefined behavior to use this value
33+
34+
#[rustc_layout_scalar_valid_range_start(30)]
35+
#[rustc_layout_scalar_valid_range_end(10)]
36+
struct RestrictedRange2(u32);
37+
const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
38+
//~^ ERROR it is undefined behavior to use this value
39+
2540
fn main() {}
Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-nonnull.rs:17:1
2+
--> $DIR/ub-nonnull.rs:18:1
33
|
44
LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
66
|
77
= 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
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-nonnull.rs:20:1
10+
--> $DIR/ub-nonnull.rs:21:1
1111
|
1212
LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
1414
|
1515
= 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
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-nonnull.rs:22:1
18+
--> $DIR/ub-nonnull.rs:23:1
1919
|
2020
LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
2222
|
2323
= 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
2424

25-
error: aborting due to 3 previous errors
25+
error[E0080]: it is undefined behavior to use this value
26+
--> $DIR/ub-nonnull.rs:31:1
27+
|
28+
LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30
30+
|
31+
= 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
32+
33+
error[E0080]: it is undefined behavior to use this value
34+
--> $DIR/ub-nonnull.rs:37:1
35+
|
36+
LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30
38+
|
39+
= 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
40+
41+
error: aborting due to 5 previous errors
2642

2743
For more information about this error, try `rustc --explain E0080`.

‎src/test/ui/consts/const-eval/ub-ref.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![feature(const_transmute)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
use std::mem;
1415

‎src/test/ui/consts/const-eval/ub-ref.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-ref.rs:15:1
2+
--> $DIR/ub-ref.rs:16:1
33
|
44
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference
66
|
77
= 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
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-ref.rs:18:1
10+
--> $DIR/ub-ref.rs:19:1
1111
|
1212
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
1414
|
1515
= 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
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-ref.rs:21:1
18+
--> $DIR/ub-ref.rs:22:1
1919
|
2020
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
2222
|
2323
= 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
2424

2525
error[E0080]: it is undefined behavior to use this value
26-
--> $DIR/ub-ref.rs:24:1
26+
--> $DIR/ub-ref.rs:25:1
2727
|
2828
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
29-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain bytes
3030
|
3131
= 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
3232

3333
error[E0080]: it is undefined behavior to use this value
34-
--> $DIR/ub-ref.rs:27:1
34+
--> $DIR/ub-ref.rs:28:1
3535
|
3636
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference

‎src/test/ui/consts/const-eval/ub-uninhabit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![feature(const_transmute)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
use std::mem;
1415

‎src/test/ui/consts/const-eval/ub-uninhabit.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-uninhabit.rs:18:1
2+
--> $DIR/ub-uninhabit.rs:19:1
33
|
44
LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
66
|
77
= 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
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-uninhabit.rs:21:1
10+
--> $DIR/ub-uninhabit.rs:22:1
1111
|
1212
LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
1414
|
1515
= 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
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-uninhabit.rs:24:1
18+
--> $DIR/ub-uninhabit.rs:25:1
1919
|
2020
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at [0]

‎src/test/ui/consts/const-eval/ub-upvars.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![feature(const_transmute,const_let)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
use std::mem;
1415

‎src/test/ui/consts/const-eval/ub-upvars.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-upvars.rs:15:1
2+
--> $DIR/ub-upvars.rs:16:1
33
|
44
LL | / const BAD_UPVAR: &FnOnce() = &{ //~ ERROR it is undefined behavior to use this value
55
LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
66
LL | | let another_var = 13;
77
LL | | move || { let _ = bad_ref; let _ = another_var; }
88
LL | | };
9-
| |__^ type validation failed: encountered 0 at .<deref>.<closure-var(bad_ref)>, but expected something greater or equal to 1
9+
| |__^ type validation failed: encountered 0 at .<deref>.<dyn-downcast>.<closure-var(bad_ref)>, but expected something greater or equal to 1
1010
|
1111
= 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
1212

‎src/test/ui/consts/const-eval/union-ub-fat-ptr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![allow(unused)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
// normalize-stderr-test "alignment \d+" -> "alignment N"
1415
// normalize-stderr-test "offset \d+" -> "offset N"

‎src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,109 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/union-ub-fat-ptr.rs:87:1
2+
--> $DIR/union-ub-fat-ptr.rs:88:1
33
|
44
LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
66
|
77
= 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
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/union-ub-fat-ptr.rs:90:1
10+
--> $DIR/union-ub-fat-ptr.rs:91:1
1111
|
1212
LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
1414
|
1515
= 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
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/union-ub-fat-ptr.rs:93:1
18+
--> $DIR/union-ub-fat-ptr.rs:94:1
1919
|
2020
LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
2222
|
2323
= 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
2424

2525
error[E0080]: it is undefined behavior to use this value
26-
--> $DIR/union-ub-fat-ptr.rs:99:1
26+
--> $DIR/union-ub-fat-ptr.rs:100:1
2727
|
2828
LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
3030
|
3131
= 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
3232

3333
error[E0080]: it is undefined behavior to use this value
34-
--> $DIR/union-ub-fat-ptr.rs:102:1
34+
--> $DIR/union-ub-fat-ptr.rs:103:1
3535
|
3636
LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
3838
|
3939
= 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
4040

4141
error[E0080]: it is undefined behavior to use this value
42-
--> $DIR/union-ub-fat-ptr.rs:106:1
42+
--> $DIR/union-ub-fat-ptr.rs:107:1
4343
|
4444
LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
4545
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
4646
|
4747
= 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
4848

4949
error[E0080]: it is undefined behavior to use this value
50-
--> $DIR/union-ub-fat-ptr.rs:109:1
50+
--> $DIR/union-ub-fat-ptr.rs:110:1
5151
|
5252
LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
5353
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
5454
|
5555
= 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
5656

5757
error[E0080]: it is undefined behavior to use this value
58-
--> $DIR/union-ub-fat-ptr.rs:112:1
58+
--> $DIR/union-ub-fat-ptr.rs:113:1
5959
|
6060
LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
6161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
6262
|
6363
= 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
6464

6565
error[E0080]: it is undefined behavior to use this value
66-
--> $DIR/union-ub-fat-ptr.rs:116:1
66+
--> $DIR/union-ub-fat-ptr.rs:117:1
6767
|
6868
LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
69-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
69+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.<dyn-downcast>, but expected something less or equal to 1
7070
|
7171
= 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
7272

7373
error[E0080]: it is undefined behavior to use this value
74-
--> $DIR/union-ub-fat-ptr.rs:120:1
74+
--> $DIR/union-ub-fat-ptr.rs:121:1
7575
|
7676
LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
77-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something less or equal to 1
7878
|
7979
= 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
8080

8181
error[E0080]: it is undefined behavior to use this value
82-
--> $DIR/union-ub-fat-ptr.rs:126:1
82+
--> $DIR/union-ub-fat-ptr.rs:127:1
8383
|
8484
LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
85-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
85+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something less or equal to 1
8686
|
8787
= 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
8888

8989
error[E0080]: it is undefined behavior to use this value
90-
--> $DIR/union-ub-fat-ptr.rs:129:1
90+
--> $DIR/union-ub-fat-ptr.rs:130:1
9191
|
9292
LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
93-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something less or equal to 1
9494
|
9595
= 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
9696

9797
error[E0080]: it is undefined behavior to use this value
98-
--> $DIR/union-ub-fat-ptr.rs:133:1
98+
--> $DIR/union-ub-fat-ptr.rs:134:1
9999
|
100100
LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
101101
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
102102
|
103103
= 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
104104

105105
error[E0080]: it is undefined behavior to use this value
106-
--> $DIR/union-ub-fat-ptr.rs:136:1
106+
--> $DIR/union-ub-fat-ptr.rs:137:1
107107
|
108108
LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
109109
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0

‎src/test/ui/consts/const-eval/union-ub.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
12+
1113
union DummyUnion {
1214
u8: u8,
1315
bool: bool,

‎src/test/ui/consts/const-eval/union-ub.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/union-ub.rs:36:1
2+
--> $DIR/union-ub.rs:38:1
33
|
44
LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool};
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 0..=1
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something less or equal to 1
66
|
77
= 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
88

0 commit comments

Comments
 (0)
Please sign in to comment.