Skip to content

Commit 8961063

Browse files
committed
Handle some cases of StructWrappedNullablePointer.
... plus a bunch of minor refactorings.
1 parent 51c5b63 commit 8961063

File tree

2 files changed

+130
-54
lines changed

2 files changed

+130
-54
lines changed

src/interpreter.rs

Lines changed: 130 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc::traits::{self, ProjectionMode};
66
use rustc::ty::fold::TypeFoldable;
77
use rustc::ty::layout::{self, Layout, Size};
88
use rustc::ty::subst::{self, Subst, Substs};
9-
use rustc::ty::{self, TyCtxt};
9+
use rustc::ty::{self, Ty, TyCtxt};
1010
use rustc::util::nodemap::DefIdMap;
1111
use std::cell::RefCell;
1212
use std::ops::{Deref, DerefMut};
@@ -413,7 +413,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
413413
Ok(target)
414414
}
415415

416-
fn drop(&mut self, ptr: Pointer, ty: ty::Ty<'tcx>) -> EvalResult<()> {
416+
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
417417
if !self.type_needs_drop(ty) {
418418
self.log(1, || print!("no need to drop {:?}", ty));
419419
return Ok(());
@@ -455,7 +455,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
455455
Ok(())
456456
}
457457

458-
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: ty::Ty<'tcx>) -> EvalResult<u64> {
458+
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
459459
use rustc::ty::layout::Layout::*;
460460
let adt_layout = self.type_layout(adt_ty);
461461

@@ -466,16 +466,14 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
466466
}
467467

468468
RawNullablePointer { nndiscr, .. } => {
469-
let not_null = match self.memory.read_usize(adt_ptr) {
470-
Ok(0) => false,
471-
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
472-
Err(e) => return Err(e),
473-
};
474-
assert!(nndiscr == 0 || nndiscr == 1);
475-
if not_null { nndiscr } else { 1 - nndiscr }
469+
self.read_nonnull_discriminant_value(adt_ptr, nndiscr)?
476470
}
477471

478-
StructWrappedNullablePointer { .. } => unimplemented!(),
472+
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
473+
let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield);
474+
let nonnull = adt_ptr.offset(offset.bytes() as isize);
475+
self.read_nonnull_discriminant_value(nonnull, nndiscr)?
476+
}
479477

480478
// The discriminant_value intrinsic returns 0 for non-sum types.
481479
Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
@@ -485,6 +483,16 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
485483
Ok(discr_val)
486484
}
487485

486+
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<u64> {
487+
let not_null = match self.memory.read_usize(ptr) {
488+
Ok(0) => false,
489+
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
490+
Err(e) => return Err(e),
491+
};
492+
assert!(nndiscr == 0 || nndiscr == 1);
493+
Ok(if not_null { nndiscr } else { 1 - nndiscr })
494+
}
495+
488496
fn call_intrinsic(
489497
&mut self,
490498
name: &str,
@@ -793,6 +801,23 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
793801
}
794802
}
795803

804+
StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield } => {
805+
if let mir::AggregateKind::Adt(_, variant, _) = *kind {
806+
if nndiscr == variant as u64 {
807+
let offsets = iter::once(0)
808+
.chain(nonnull.offset_after_field.iter().map(|s| s.bytes()));
809+
try!(self.assign_fields(dest, offsets, operands));
810+
} else {
811+
assert_eq!(operands.len(), 0);
812+
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield);
813+
let dest = dest.offset(offset.bytes() as isize);
814+
try!(self.memory.write_isize(dest, 0));
815+
}
816+
} else {
817+
panic!("tried to assign {:?} to Layout::RawNullablePointer", kind);
818+
}
819+
}
820+
796821
CEnum { discr, signed, .. } => {
797822
assert_eq!(operands.len(), 0);
798823
if let mir::AggregateKind::Adt(adt_def, variant, _) = *kind {
@@ -900,6 +925,73 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
900925
Ok(())
901926
}
902927

928+
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> Size {
929+
// Skip the constant 0 at the start meant for LLVM GEP.
930+
let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
931+
932+
// Handle the field index for the outer non-null variant.
933+
let inner_ty = match ty.sty {
934+
ty::TyEnum(adt_def, substs) => {
935+
let variant = &adt_def.variants[nndiscr as usize];
936+
let index = path.next().unwrap();
937+
let field = &variant.fields[index];
938+
field.ty(self.tcx, substs)
939+
}
940+
_ => panic!(
941+
"non-enum for StructWrappedNullablePointer: {}",
942+
ty,
943+
),
944+
};
945+
946+
self.field_path_offset(inner_ty, path)
947+
}
948+
949+
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> Size {
950+
let mut offset = Size::from_bytes(0);
951+
952+
// Skip the initial 0 intended for LLVM GEP.
953+
for field_index in path {
954+
let field_offset = self.get_field_offset(ty, field_index);
955+
ty = self.get_field_ty(ty, field_index);
956+
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
957+
}
958+
959+
offset
960+
}
961+
962+
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> Ty<'tcx> {
963+
match ty.sty {
964+
ty::TyStruct(adt_def, substs) => {
965+
adt_def.struct_variant().fields[field_index].ty(self.tcx, substs)
966+
}
967+
968+
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
969+
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
970+
ty::TyBox(ty) => {
971+
assert_eq!(field_index, 0);
972+
ty
973+
}
974+
_ => panic!("can't handle type: {:?}", ty),
975+
}
976+
}
977+
978+
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> Size {
979+
let layout = self.type_layout(ty);
980+
981+
use rustc::ty::layout::Layout::*;
982+
match *layout {
983+
Univariant { .. } => {
984+
assert_eq!(field_index, 0);
985+
Size::from_bytes(0)
986+
}
987+
FatPointer { .. } => {
988+
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size;
989+
Size::from_bytes(bytes as u64)
990+
}
991+
_ => panic!("can't handle type: {:?}, with layout: {:?}", ty, layout),
992+
}
993+
}
994+
903995
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
904996
use rustc::mir::repr::Operand::*;
905997
match *op {
@@ -944,35 +1036,42 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
9441036
use rustc::mir::repr::ProjectionElem::*;
9451037
match proj.elem {
9461038
Field(field, _) => {
1039+
use rustc::ty::layout::Layout::*;
9471040
let variant = match *base_layout {
948-
Layout::Univariant { ref variant, .. } => variant,
949-
Layout::General { ref variants, .. } => {
1041+
Univariant { ref variant, .. } => variant,
1042+
General { ref variants, .. } => {
9501043
if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
9511044
&variants[variant_idx]
9521045
} else {
9531046
panic!("field access on enum had no variant index");
9541047
}
9551048
}
956-
Layout::RawNullablePointer { .. } => {
1049+
RawNullablePointer { .. } => {
9571050
assert_eq!(field.index(), 0);
9581051
return Ok(base);
9591052
}
1053+
StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
9601054
_ => panic!("field access on non-product type: {:?}", base_layout),
9611055
};
9621056

9631057
let offset = variant.field_offset(field.index()).bytes();
9641058
base.ptr.offset(offset as isize)
9651059
},
9661060

967-
Downcast(_, variant) => match *base_layout {
968-
Layout::General { discr, .. } => {
969-
return Ok(Lvalue {
970-
ptr: base.ptr.offset(discr.size().bytes() as isize),
971-
extra: LvalueExtra::DowncastVariant(variant),
972-
});
1061+
Downcast(_, variant) => {
1062+
use rustc::ty::layout::Layout::*;
1063+
match *base_layout {
1064+
General { discr, .. } => {
1065+
return Ok(Lvalue {
1066+
ptr: base.ptr.offset(discr.size().bytes() as isize),
1067+
extra: LvalueExtra::DowncastVariant(variant),
1068+
});
1069+
}
1070+
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1071+
return Ok(base);
1072+
}
1073+
_ => panic!("variant downcast on non-aggregate: {:?}", base_layout),
9731074
}
974-
Layout::RawNullablePointer { .. } => return Ok(base),
975-
_ => panic!("variant downcast on non-aggregate type: {:?}", base_layout),
9761075
},
9771076

9781077
Deref => {
@@ -1052,24 +1151,24 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
10521151
}
10531152
}
10541153

1055-
fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> ty::Ty<'tcx> {
1154+
fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
10561155
self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx))
10571156
}
10581157

1059-
fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> ty::Ty<'tcx> {
1158+
fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
10601159
self.monomorphize(self.mir().operand_ty(self.tcx, operand))
10611160
}
10621161

1063-
fn monomorphize(&self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> {
1162+
fn monomorphize(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
10641163
let substituted = ty.subst(self.tcx, self.substs());
10651164
self.tcx.normalize_associated_type(&substituted)
10661165
}
10671166

1068-
fn type_needs_drop(&self, ty: ty::Ty<'tcx>) -> bool {
1167+
fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
10691168
self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
10701169
}
10711170

1072-
fn move_(&mut self, src: Pointer, dest: Pointer, ty: ty::Ty<'tcx>) -> EvalResult<()> {
1171+
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
10731172
let size = self.type_size(ty);
10741173
self.memory.copy(src, dest, size)?;
10751174
if self.type_needs_drop(ty) {
@@ -1078,15 +1177,15 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
10781177
Ok(())
10791178
}
10801179

1081-
fn type_is_sized(&self, ty: ty::Ty<'tcx>) -> bool {
1180+
fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
10821181
ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
10831182
}
10841183

1085-
fn type_size(&self, ty: ty::Ty<'tcx>) -> usize {
1184+
fn type_size(&self, ty: Ty<'tcx>) -> usize {
10861185
self.type_layout(ty).size(&self.tcx.data_layout).bytes() as usize
10871186
}
10881187

1089-
fn type_layout(&self, ty: ty::Ty<'tcx>) -> &'tcx Layout {
1188+
fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout {
10901189
// TODO(solson): Is this inefficient? Needs investigation.
10911190
let ty = self.monomorphize(ty);
10921191

@@ -1096,7 +1195,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
10961195
})
10971196
}
10981197

1099-
pub fn read_primval(&mut self, ptr: Pointer, ty: ty::Ty<'tcx>) -> EvalResult<PrimVal> {
1198+
pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
11001199
use syntax::ast::{IntTy, UintTy};
11011200
let val = match ty.sty {
11021201
ty::TyBool => PrimVal::Bool(self.memory.read_bool(ptr)?),

tests/compile-fail/bugs/struct_wrapped_nullable_pointer.rs

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)