Skip to content

Commit ce95ae5

Browse files
committed
correctly implement pointers to enum variant constructors
1 parent b6e79db commit ce95ae5

File tree

3 files changed

+50
-14
lines changed

3 files changed

+50
-14
lines changed

src/eval_context.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -685,22 +685,25 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
685685
let path = discrfield.iter().skip(2).map(|&i| i as usize);
686686

687687
// Handle the field index for the outer non-null variant.
688-
let inner_ty = match ty.sty {
688+
let (inner_offset, inner_ty) = match ty.sty {
689689
ty::TyAdt(adt_def, substs) => {
690690
let variant = &adt_def.variants[nndiscr as usize];
691691
let index = discrfield[1];
692692
let field = &variant.fields[index as usize];
693-
field.ty(self.tcx, substs)
693+
(self.get_field_offset(ty, index as usize)?, field.ty(self.tcx, substs))
694694
}
695695
_ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
696696
};
697697

698-
self.field_path_offset_and_ty(inner_ty, path)
698+
self.field_path_offset_and_ty(inner_offset, inner_ty, path)
699699
}
700700

701-
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
702-
let mut offset = Size::from_bytes(0);
703-
701+
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(
702+
&self,
703+
mut offset: Size,
704+
mut ty: Ty<'tcx>,
705+
path: I,
706+
) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
704707
// Skip the initial 0 intended for LLVM GEP.
705708
for field_index in path {
706709
let field_offset = self.get_field_offset(ty, field_index)?;
@@ -747,6 +750,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
747750
let bytes = field_index as u64 * self.memory.pointer_size();
748751
Ok(Size::from_bytes(bytes))
749752
}
753+
StructWrappedNullablePointer { ref nonnull, .. } => {
754+
Ok(nonnull.offsets[field_index])
755+
}
750756
_ => {
751757
let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
752758
Err(EvalError::Unimplemented(msg))
@@ -761,6 +767,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
761767
match *layout {
762768
Univariant { ref variant, .. } => Ok(variant.offsets.len()),
763769
FatPointer { .. } => Ok(2),
770+
StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len()),
764771
_ => {
765772
let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
766773
Err(EvalError::Unimplemented(msg))

src/terminator/mod.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,27 +238,46 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
238238
let (lvalue, target) = destination.expect("tuple struct constructors can't diverge");
239239
let dest_ty = self.tcx.item_type(adt_def.did);
240240
let dest_layout = self.type_layout(dest_ty)?;
241-
let disr = v.disr_val.to_u128_unchecked();
241+
trace!("layout({:?}) = {:#?}", dest_ty, dest_layout);
242242
match *dest_layout {
243243
Layout::Univariant { ref variant, .. } => {
244-
assert_eq!(disr, 0);
244+
let disr_val = v.disr_val.to_u128_unchecked();
245+
assert_eq!(disr_val, 0);
245246
let offsets = variant.offsets.iter().map(|s| s.bytes());
246247

247248
self.assign_fields(lvalue, offsets, args)?;
248249
},
249250
Layout::General { discr, ref variants, .. } => {
250-
// FIXME: report a proper error for invalid discriminants
251-
// right now we simply go into index out of bounds
251+
let disr_val = v.disr_val.to_u128_unchecked();
252252
let discr_size = discr.size().bytes();
253253
self.assign_discr_and_fields(
254254
lvalue,
255-
variants[disr as usize].offsets.iter().cloned().map(Size::bytes),
255+
variants[disr_val as usize].offsets.iter().cloned().map(Size::bytes),
256256
args,
257-
disr,
257+
disr_val,
258258
discr_size,
259259
)?;
260260
},
261-
Layout::StructWrappedNullablePointer { .. } |
261+
Layout::StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
262+
let disr_val = v.disr_val.to_u128_unchecked();
263+
if nndiscr as u128 == disr_val {
264+
let offsets = nonnull.offsets.iter().map(|s| s.bytes());
265+
self.assign_fields(lvalue, offsets, args)?;
266+
} else {
267+
for (_, ty) in args {
268+
assert_eq!(self.type_size(ty)?, Some(0));
269+
}
270+
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
271+
272+
// FIXME(solson)
273+
let dest = self.force_allocation(lvalue)?.to_ptr();
274+
275+
let dest = dest.offset(offset.bytes());
276+
let dest_size = self.type_size(ty)?
277+
.expect("bad StructWrappedNullablePointer discrfield");
278+
self.memory.write_int(dest, 0, dest_size)?;
279+
}
280+
},
262281
Layout::RawNullablePointer { .. } => {
263282
assert_eq!(args.len(), 1);
264283
let (val, ty) = args.pop().unwrap();
@@ -307,7 +326,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
307326
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
308327
use rustc::ty::layout::Layout::*;
309328
let adt_layout = self.type_layout(adt_ty)?;
310-
trace!("read_discriminant_value {:?}", adt_layout);
329+
trace!("read_discriminant_value {:#?}", adt_layout);
311330

312331
let discr_val = match *adt_layout {
313332
General { discr, .. } | CEnum { discr, signed: false, .. } => {
@@ -344,6 +363,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
344363
}
345364

346365
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u128, discr_size: u64) -> EvalResult<'tcx, u128> {
366+
trace!("read_nonnull_discriminant_value: {:?}, {}, {}", ptr, nndiscr, discr_size);
347367
let not_null = match self.memory.read_uint(ptr, discr_size) {
348368
Ok(0) => false,
349369
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,

tests/run-pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ struct A<'a> {
77
#[derive(Copy, Clone, PartialEq, Debug)]
88
struct B<'a>(i32, &'a i32);
99

10+
#[derive(Copy, Clone, PartialEq, Debug)]
11+
enum C<'a> {
12+
Value(i32, &'a i32),
13+
#[allow(dead_code)]
14+
NoValue,
15+
}
16+
1017
fn main() {
1118
let x = 5;
1219
let a = A { x: 99, y: &x };
@@ -17,6 +24,8 @@ fn main() {
1724
//let f: for<'a> fn(i32, &'a i32) -> B<'a> = B;
1825
//assert_eq!(Some(B(42, &x)), Some(f(42, &x)));
1926
assert_eq!(B(42, &x), foo(&x, B));
27+
let f = C::Value;
28+
assert_eq!(C::Value(42, &x), f(42, &x));
2029
}
2130

2231
fn foo<'a, F: Fn(i32, &'a i32) -> B<'a>>(i: &'a i32, f: F) -> B<'a> {

0 commit comments

Comments
 (0)