Skip to content

Commit 59fa6bd

Browse files
committed
Auto merge of #52712 - oli-obk:const_eval_cleanups, r=RalfJung
Reintroduce `Undef` and properly check constant value sizes r? @RalfJung cc @eddyb basically all kinds of silent failures that never occurred are assertions now
2 parents 88e0ff1 + 828aebf commit 59fa6bd

File tree

28 files changed

+627
-617
lines changed

28 files changed

+627
-617
lines changed

src/librustc/ich/impls_ty.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,11 @@ for ::mir::interpret::ConstValue<'gcx> {
392392
}
393393
}
394394

395+
impl_stable_hash_for!(enum mir::interpret::ScalarMaybeUndef {
396+
Scalar(v),
397+
Undef
398+
});
399+
395400
impl_stable_hash_for!(enum mir::interpret::Value {
396401
Scalar(v),
397402
ScalarPair(a, b),
@@ -466,9 +471,9 @@ for ::mir::interpret::Scalar {
466471

467472
mem::discriminant(self).hash_stable(hcx, hasher);
468473
match *self {
469-
Bits { bits, defined } => {
474+
Bits { bits, size } => {
470475
bits.hash_stable(hcx, hasher);
471-
defined.hash_stable(hcx, hasher);
476+
size.hash_stable(hcx, hasher);
472477
},
473478
Ptr(ptr) => ptr.hash_stable(hcx, hasher),
474479
}

src/librustc/mir/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use self::error::{
1313
FrameInfo, ConstEvalResult,
1414
};
1515

16-
pub use self::value::{Scalar, Value, ConstValue};
16+
pub use self::value::{Scalar, Value, ConstValue, ScalarMaybeUndef};
1717

1818
use std::fmt;
1919
use mir;

src/librustc/mir/interpret/value.rs

+104-86
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,38 @@ pub enum ConstValue<'tcx> {
1515
/// to allow HIR creation to happen for everything before needing to be able to run constant
1616
/// evaluation
1717
Unevaluated(DefId, &'tcx Substs<'tcx>),
18-
/// Used only for types with layout::abi::Scalar ABI and ZSTs which use Scalar::undef()
18+
/// Used only for types with layout::abi::Scalar ABI and ZSTs
1919
Scalar(Scalar),
2020
/// Used only for types with layout::abi::ScalarPair
21-
ScalarPair(Scalar, Scalar),
21+
///
22+
/// The second field may be undef in case of `Option<usize>::None`
23+
ScalarPair(Scalar, ScalarMaybeUndef),
2224
/// Used only for the remaining cases. An allocation + offset into the allocation
2325
ByRef(&'tcx Allocation, Size),
2426
}
2527

2628
impl<'tcx> ConstValue<'tcx> {
2729
#[inline]
28-
pub fn from_byval_value(val: Value) -> Self {
29-
match val {
30+
pub fn from_byval_value(val: Value) -> EvalResult<'static, Self> {
31+
Ok(match val {
3032
Value::ByRef(..) => bug!(),
31-
Value::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
32-
Value::Scalar(val) => ConstValue::Scalar(val),
33-
}
33+
Value::ScalarPair(a, b) => ConstValue::ScalarPair(a.unwrap_or_err()?, b),
34+
Value::Scalar(val) => ConstValue::Scalar(val.unwrap_or_err()?),
35+
})
3436
}
3537

3638
#[inline]
3739
pub fn to_byval_value(&self) -> Option<Value> {
3840
match *self {
3941
ConstValue::Unevaluated(..) |
4042
ConstValue::ByRef(..) => None,
41-
ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)),
42-
ConstValue::Scalar(val) => Some(Value::Scalar(val)),
43+
ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a.into(), b)),
44+
ConstValue::Scalar(val) => Some(Value::Scalar(val.into())),
4345
}
4446
}
4547

4648
#[inline]
47-
pub fn from_scalar(val: Scalar) -> Self {
48-
ConstValue::Scalar(val)
49-
}
50-
51-
#[inline]
52-
pub fn to_scalar(&self) -> Option<Scalar> {
49+
pub fn try_to_scalar(&self) -> Option<Scalar> {
5350
match *self {
5451
ConstValue::Unevaluated(..) |
5552
ConstValue::ByRef(..) |
@@ -60,12 +57,12 @@ impl<'tcx> ConstValue<'tcx> {
6057

6158
#[inline]
6259
pub fn to_bits(&self, size: Size) -> Option<u128> {
63-
self.to_scalar()?.to_bits(size).ok()
60+
self.try_to_scalar()?.to_bits(size).ok()
6461
}
6562

6663
#[inline]
6764
pub fn to_ptr(&self) -> Option<Pointer> {
68-
self.to_scalar()?.to_ptr().ok()
65+
self.try_to_scalar()?.to_ptr().ok()
6966
}
7067
}
7168

@@ -81,8 +78,8 @@ impl<'tcx> ConstValue<'tcx> {
8178
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
8279
pub enum Value {
8380
ByRef(Scalar, Align),
84-
Scalar(Scalar),
85-
ScalarPair(Scalar, Scalar),
81+
Scalar(ScalarMaybeUndef),
82+
ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef),
8683
}
8784

8885
impl<'tcx> ty::TypeFoldable<'tcx> for Value {
@@ -98,23 +95,27 @@ impl<'tcx> Scalar {
9895
pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
9996
Scalar::Bits {
10097
bits: 0,
101-
defined: cx.data_layout().pointer_size.bits() as u8,
98+
size: cx.data_layout().pointer_size.bytes() as u8,
10299
}
103100
}
104101

102+
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
103+
ScalarMaybeUndef::Scalar(self).to_value_with_len(len, cx)
104+
}
105+
106+
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
107+
ScalarMaybeUndef::Scalar(self).to_value_with_vtable(vtable)
108+
}
109+
105110
pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
106111
let layout = cx.data_layout();
107112
match self {
108-
Scalar::Bits { bits, defined } => {
109-
let pointer_size = layout.pointer_size.bits() as u8;
110-
if defined < pointer_size {
111-
err!(ReadUndefBytes)
112-
} else {
113-
Ok(Scalar::Bits {
114-
bits: layout.signed_offset(bits as u64, i)? as u128,
115-
defined: pointer_size,
116-
})
117-
}
113+
Scalar::Bits { bits, size } => {
114+
assert_eq!(size as u64, layout.pointer_size.bytes());
115+
Ok(Scalar::Bits {
116+
bits: layout.signed_offset(bits as u64, i)? as u128,
117+
size,
118+
})
118119
}
119120
Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
120121
}
@@ -123,65 +124,43 @@ impl<'tcx> Scalar {
123124
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
124125
let layout = cx.data_layout();
125126
match self {
126-
Scalar::Bits { bits, defined } => {
127-
let pointer_size = layout.pointer_size.bits() as u8;
128-
if defined < pointer_size {
129-
err!(ReadUndefBytes)
130-
} else {
131-
Ok(Scalar::Bits {
132-
bits: layout.offset(bits as u64, i.bytes())? as u128,
133-
defined: pointer_size,
134-
})
135-
}
127+
Scalar::Bits { bits, size } => {
128+
assert_eq!(size as u64, layout.pointer_size.bytes());
129+
Ok(Scalar::Bits {
130+
bits: layout.offset(bits as u64, i.bytes())? as u128,
131+
size,
132+
})
136133
}
137134
Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
138135
}
139136
}
140137

141-
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
138+
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
142139
let layout = cx.data_layout();
143140
match self {
144-
Scalar::Bits { bits, defined } => {
145-
let pointer_size = layout.pointer_size.bits() as u8;
146-
if defined < pointer_size {
147-
err!(ReadUndefBytes)
148-
} else {
149-
Ok(Scalar::Bits {
150-
bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
151-
defined: pointer_size,
152-
})
153-
}
141+
Scalar::Bits { bits, size } => {
142+
assert_eq!(size as u64, layout.pointer_size.bytes());
143+
Scalar::Bits {
144+
bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
145+
size,
146+
}
154147
}
155-
Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
148+
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
156149
}
157150
}
158151

159-
pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
152+
pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> bool {
160153
match self {
161-
Scalar::Bits {
162-
bits, defined,
163-
} => if defined < cx.data_layout().pointer_size.bits() as u8 {
164-
err!(ReadUndefBytes)
165-
} else {
166-
Ok(bits == 0)
154+
Scalar::Bits { bits, size } => {
155+
assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
156+
bits == 0
167157
},
168-
Scalar::Ptr(_) => Ok(false),
158+
Scalar::Ptr(_) => false,
169159
}
170160
}
171161

172-
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
173-
Value::ScalarPair(self, Scalar::Bits {
174-
bits: len as u128,
175-
defined: cx.data_layout().pointer_size.bits() as u8,
176-
})
177-
}
178-
179-
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
180-
Value::ScalarPair(self, Scalar::Ptr(vtable))
181-
}
182-
183162
pub fn to_value(self) -> Value {
184-
Value::Scalar(self)
163+
Value::Scalar(ScalarMaybeUndef::Scalar(self))
185164
}
186165
}
187166

@@ -199,8 +178,9 @@ impl From<Pointer> for Scalar {
199178
pub enum Scalar {
200179
/// The raw bytes of a simple value.
201180
Bits {
202-
/// The first `defined` number of bits are valid
203-
defined: u8,
181+
/// The first `size` bytes are the value.
182+
/// Do not try to read less or more bytes that that
183+
size: u8,
204184
bits: u128,
205185
},
206186

@@ -210,25 +190,63 @@ pub enum Scalar {
210190
Ptr(Pointer),
211191
}
212192

213-
impl<'tcx> Scalar {
214-
pub fn undef() -> Self {
215-
Scalar::Bits { bits: 0, defined: 0 }
193+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
194+
pub enum ScalarMaybeUndef {
195+
Scalar(Scalar),
196+
Undef,
197+
}
198+
199+
impl From<Scalar> for ScalarMaybeUndef {
200+
fn from(s: Scalar) -> Self {
201+
ScalarMaybeUndef::Scalar(s)
202+
}
203+
}
204+
205+
impl ScalarMaybeUndef {
206+
pub fn unwrap_or_err(self) -> EvalResult<'static, Scalar> {
207+
match self {
208+
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
209+
ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
210+
}
211+
}
212+
213+
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
214+
Value::ScalarPair(self, Scalar::Bits {
215+
bits: len as u128,
216+
size: cx.data_layout().pointer_size.bytes() as u8,
217+
}.into())
216218
}
217219

220+
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
221+
Value::ScalarPair(self, Scalar::Ptr(vtable).into())
222+
}
223+
224+
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
225+
match self {
226+
ScalarMaybeUndef::Scalar(scalar) => {
227+
scalar.ptr_offset(i, cx).map(ScalarMaybeUndef::Scalar)
228+
},
229+
ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
230+
}
231+
}
232+
}
233+
234+
impl<'tcx> Scalar {
218235
pub fn from_bool(b: bool) -> Self {
219-
// FIXME: can we make defined `1`?
220-
Scalar::Bits { bits: b as u128, defined: 8 }
236+
Scalar::Bits { bits: b as u128, size: 1 }
221237
}
222238

223239
pub fn from_char(c: char) -> Self {
224-
Scalar::Bits { bits: c as u128, defined: 32 }
240+
Scalar::Bits { bits: c as u128, size: 4 }
225241
}
226242

227-
pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
243+
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
228244
match self {
229-
Scalar::Bits { .. } if size.bits() == 0 => bug!("to_bits cannot be used with zsts"),
230-
Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits),
231-
Scalar::Bits { .. } => err!(ReadUndefBytes),
245+
Scalar::Bits { bits, size } => {
246+
assert_eq!(target_size.bytes(), size as u64);
247+
assert_ne!(size, 0, "to_bits cannot be used with zsts");
248+
Ok(bits)
249+
}
232250
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
233251
}
234252
}
@@ -256,8 +274,8 @@ impl<'tcx> Scalar {
256274

257275
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
258276
match self {
259-
Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
260-
Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
277+
Scalar::Bits { bits: 0, size: 1 } => Ok(false),
278+
Scalar::Bits { bits: 1, size: 1 } => Ok(true),
261279
_ => err!(InvalidBool),
262280
}
263281
}

0 commit comments

Comments
 (0)