Skip to content

Commit d42a7d0

Browse files
committed
fix null optimizations for smaller than pointer enums
fixes rust-lang#76
1 parent 1c40fb0 commit d42a7d0

File tree

3 files changed

+32
-17
lines changed

3 files changed

+32
-17
lines changed

src/interpreter/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
203203
PrimVal::from_uint_with_size(n, self.memory.pointer_size())
204204
}
205205

206-
fn isize_primval(&self, n: i64) -> PrimVal {
207-
PrimVal::from_int_with_size(n, self.memory.pointer_size())
208-
}
209-
210206
fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
211207
// FIXME: cache these allocs
212208
let ptr = self.memory.allocate(s.len(), 1)?;
@@ -523,7 +519,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
523519
self.write_value(value, dest, value_ty)?;
524520
} else {
525521
assert_eq!(operands.len(), 0);
526-
let zero = self.isize_primval(0);
522+
let value_size = self.type_size(dest_ty).expect("pointer types are sized");
523+
let zero = PrimVal::from_int_with_size(0, value_size);
527524
self.write_primval(dest, zero)?;
528525
}
529526
} else {
@@ -541,13 +538,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
541538
let operand_ty = self.operand_ty(operand);
542539
assert_eq!(self.type_size(operand_ty), Some(0));
543540
}
544-
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
541+
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
545542

546543
// FIXME(solson)
547544
let dest = self.force_allocation(dest)?.to_ptr();
548545

549546
let dest = dest.offset(offset.bytes() as isize);
550-
try!(self.memory.write_isize(dest, 0));
547+
let dest_size = self.type_size(ty).unwrap_or(self.memory.pointer_size());
548+
try!(self.memory.write_int(dest, 0, dest_size));
551549
}
552550
} else {
553551
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
@@ -694,7 +692,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
694692
}
695693
}
696694

697-
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<'tcx, Size> {
695+
fn nonnull_offset_and_ty(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
698696
// Skip the constant 0 at the start meant for LLVM GEP.
699697
let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
700698

@@ -709,10 +707,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
709707
_ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
710708
};
711709

712-
self.field_path_offset(inner_ty, path)
710+
self.field_path_offset_and_ty(inner_ty, path)
713711
}
714712

715-
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, Size> {
713+
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
716714
let mut offset = Size::from_bytes(0);
717715

718716
// Skip the initial 0 intended for LLVM GEP.
@@ -722,7 +720,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
722720
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
723721
}
724722

725-
Ok(offset)
723+
Ok((offset, ty))
726724
}
727725

728726
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {

src/interpreter/terminator/mod.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,14 +263,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
263263
self.memory.read_int(adt_ptr, discr_size as usize)? as u64
264264
}
265265

266-
RawNullablePointer { nndiscr, .. } => {
267-
self.read_nonnull_discriminant_value(adt_ptr, nndiscr)?
266+
RawNullablePointer { nndiscr, value } => {
267+
let discr_size = value.size(&self.tcx.data_layout).bytes() as usize;
268+
self.read_nonnull_discriminant_value(adt_ptr, nndiscr, discr_size)?
268269
}
269270

270271
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
271-
let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield)?;
272+
let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
272273
let nonnull = adt_ptr.offset(offset.bytes() as isize);
273-
self.read_nonnull_discriminant_value(nonnull, nndiscr)?
274+
// only the pointer part of a fat pointer is used for this space optimization
275+
let discr_size = self.type_size(ty).unwrap_or(self.memory.pointer_size());
276+
self.read_nonnull_discriminant_value(nonnull, nndiscr, discr_size)?
274277
}
275278

276279
// The discriminant_value intrinsic returns 0 for non-sum types.
@@ -281,8 +284,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
281284
Ok(discr_val)
282285
}
283286

284-
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<'tcx, u64> {
285-
let not_null = match self.memory.read_usize(ptr) {
287+
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64, discr_size: usize) -> EvalResult<'tcx, u64> {
288+
let not_null = match self.memory.read_uint(ptr, discr_size) {
286289
Ok(0) => false,
287290
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
288291
Err(e) => return Err(e),

tests/run-pass/small_enum_size_bug.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![allow(dead_code)]
2+
3+
enum E {
4+
A = 1,
5+
B = 2,
6+
C = 3,
7+
}
8+
9+
fn main() {
10+
let enone = None::<E>;
11+
if let Some(..) = enone {
12+
panic!();
13+
}
14+
}

0 commit comments

Comments
 (0)