Skip to content

Commit c6c0685

Browse files
committed
Reintroduce Undef and properly check constant value sizes
1 parent 8c069ce commit c6c0685

File tree

20 files changed

+538
-500
lines changed

20 files changed

+538
-500
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 7 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 115 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ 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
2121
ScalarPair(Scalar, Scalar),
@@ -25,31 +25,26 @@ pub enum ConstValue<'tcx> {
2525

2626
impl<'tcx> ConstValue<'tcx> {
2727
#[inline]
28-
pub fn from_byval_value(val: Value) -> Self {
29-
match val {
28+
pub fn from_byval_value(val: Value) -> EvalResult<'static, Self> {
29+
Ok(match val {
3030
Value::ByRef(..) => bug!(),
31-
Value::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
32-
Value::Scalar(val) => ConstValue::Scalar(val),
33-
}
31+
Value::ScalarPair(a, b) => ConstValue::ScalarPair(a.read()?, b.read()?),
32+
Value::Scalar(val) => ConstValue::Scalar(val.read()?),
33+
})
3434
}
3535

3636
#[inline]
3737
pub fn to_byval_value(&self) -> Option<Value> {
3838
match *self {
3939
ConstValue::Unevaluated(..) |
4040
ConstValue::ByRef(..) => None,
41-
ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)),
42-
ConstValue::Scalar(val) => Some(Value::Scalar(val)),
41+
ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a.into(), b.into())),
42+
ConstValue::Scalar(val) => Some(Value::Scalar(val.into())),
4343
}
4444
}
4545

4646
#[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> {
47+
pub fn try_to_scalar(&self) -> Option<Scalar> {
5348
match *self {
5449
ConstValue::Unevaluated(..) |
5550
ConstValue::ByRef(..) |
@@ -60,12 +55,12 @@ impl<'tcx> ConstValue<'tcx> {
6055

6156
#[inline]
6257
pub fn to_bits(&self, size: Size) -> Option<u128> {
63-
self.to_scalar()?.to_bits(size).ok()
58+
self.try_to_scalar()?.to_bits(size).ok()
6459
}
6560

6661
#[inline]
6762
pub fn to_ptr(&self) -> Option<Pointer> {
68-
self.to_scalar()?.to_ptr().ok()
63+
self.try_to_scalar()?.to_ptr().ok()
6964
}
7065
}
7166

@@ -81,8 +76,8 @@ impl<'tcx> ConstValue<'tcx> {
8176
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
8277
pub enum Value {
8378
ByRef(Scalar, Align),
84-
Scalar(Scalar),
85-
ScalarPair(Scalar, Scalar),
79+
Scalar(ScalarMaybeUndef),
80+
ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef),
8681
}
8782

8883
impl<'tcx> ty::TypeFoldable<'tcx> for Value {
@@ -98,23 +93,23 @@ impl<'tcx> Scalar {
9893
pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
9994
Scalar::Bits {
10095
bits: 0,
101-
defined: cx.data_layout().pointer_size.bits() as u8,
96+
size: cx.data_layout().pointer_size.bytes() as u8,
10297
}
10398
}
10499

100+
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
101+
ScalarMaybeUndef::Scalar(self).to_value_with_len(len, cx)
102+
}
103+
105104
pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
106105
let layout = cx.data_layout();
107106
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-
}
107+
Scalar::Bits { bits, size } => {
108+
assert_eq!(size as u64, layout.pointer_size.bytes());
109+
Ok(Scalar::Bits {
110+
bits: layout.signed_offset(bits as u64, i)? as u128,
111+
size,
112+
})
118113
}
119114
Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
120115
}
@@ -123,65 +118,43 @@ impl<'tcx> Scalar {
123118
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
124119
let layout = cx.data_layout();
125120
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-
}
121+
Scalar::Bits { bits, size } => {
122+
assert_eq!(size as u64, layout.pointer_size.bytes());
123+
Ok(Scalar::Bits {
124+
bits: layout.offset(bits as u64, i.bytes())? as u128,
125+
size,
126+
})
136127
}
137128
Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
138129
}
139130
}
140131

141-
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
132+
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
142133
let layout = cx.data_layout();
143134
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-
})
135+
Scalar::Bits { bits, size } => {
136+
assert_eq!(size as u64, layout.pointer_size.bytes());
137+
Scalar::Bits {
138+
bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
139+
size,
140+
}
153141
}
154-
}
155-
Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
142+
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
156143
}
157144
}
158145

159-
pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
146+
pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> bool {
160147
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)
148+
Scalar::Bits { bits, size } => {
149+
assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
150+
bits == 0
167151
},
168-
Scalar::Ptr(_) => Ok(false),
152+
Scalar::Ptr(_) => false,
169153
}
170154
}
171155

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-
183156
pub fn to_value(self) -> Value {
184-
Value::Scalar(self)
157+
Value::Scalar(ScalarMaybeUndef::Scalar(self))
185158
}
186159
}
187160

@@ -199,8 +172,9 @@ impl From<Pointer> for Scalar {
199172
pub enum Scalar {
200173
/// The raw bytes of a simple value.
201174
Bits {
202-
/// The first `defined` number of bits are valid
203-
defined: u8,
175+
/// The first `size` bytes are the value.
176+
/// Do not try to read less or more bytes that that
177+
size: u8,
204178
bits: u128,
205179
},
206180

@@ -210,25 +184,81 @@ pub enum Scalar {
210184
Ptr(Pointer),
211185
}
212186

213-
impl<'tcx> Scalar {
214-
pub fn undef() -> Self {
215-
Scalar::Bits { bits: 0, defined: 0 }
187+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
188+
pub enum ScalarMaybeUndef {
189+
Scalar(Scalar),
190+
Undef,
191+
}
192+
193+
impl From<Scalar> for ScalarMaybeUndef {
194+
fn from(s: Scalar) -> Self {
195+
ScalarMaybeUndef::Scalar(s)
196+
}
197+
}
198+
199+
impl ScalarMaybeUndef {
200+
pub fn read(self) -> EvalResult<'static, Scalar> {
201+
match self {
202+
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
203+
ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
204+
}
205+
}
206+
207+
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
208+
Value::ScalarPair(self.into(), Scalar::Bits {
209+
bits: len as u128,
210+
size: cx.data_layout().pointer_size.bytes() as u8,
211+
}.into())
212+
}
213+
214+
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
215+
Value::ScalarPair(self.into(), Scalar::Ptr(vtable).into())
216+
}
217+
218+
pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
219+
match self {
220+
ScalarMaybeUndef::Scalar(scalar) => {
221+
scalar.ptr_signed_offset(i, cx).map(ScalarMaybeUndef::Scalar)
222+
},
223+
ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
224+
}
216225
}
217226

227+
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
228+
match self {
229+
ScalarMaybeUndef::Scalar(scalar) => {
230+
scalar.ptr_offset(i, cx).map(ScalarMaybeUndef::Scalar)
231+
},
232+
ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
233+
}
234+
}
235+
236+
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
237+
match self {
238+
ScalarMaybeUndef::Scalar(scalar) => {
239+
ScalarMaybeUndef::Scalar(scalar.ptr_wrapping_signed_offset(i, cx))
240+
},
241+
ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef
242+
}
243+
}
244+
}
245+
246+
impl<'tcx> Scalar {
218247
pub fn from_bool(b: bool) -> Self {
219-
// FIXME: can we make defined `1`?
220-
Scalar::Bits { bits: b as u128, defined: 8 }
248+
Scalar::Bits { bits: b as u128, size: 1 }
221249
}
222250

223251
pub fn from_char(c: char) -> Self {
224-
Scalar::Bits { bits: c as u128, defined: 32 }
252+
Scalar::Bits { bits: c as u128, size: 4 }
225253
}
226254

227-
pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
255+
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
228256
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),
257+
Scalar::Bits { bits, size } => {
258+
assert_eq!(target_size.bytes(), size as u64);
259+
assert_ne!(size, 0, "to_bits cannot be used with zsts");
260+
Ok(bits)
261+
}
232262
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
233263
}
234264
}
@@ -256,8 +286,8 @@ impl<'tcx> Scalar {
256286

257287
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
258288
match self {
259-
Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
260-
Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
289+
Scalar::Bits { bits: 0, size: 1 } => Ok(false),
290+
Scalar::Bits { bits: 1, size: 1 } => Ok(true),
261291
_ => err!(InvalidBool),
262292
}
263293
}

0 commit comments

Comments
 (0)