Skip to content

Commit 6e13c3c

Browse files
authored
Merge pull request rust-lang#64 from oli-obk/bugfixes
Bugfixes
2 parents 10ab168 + f1f6205 commit 6e13c3c

File tree

10 files changed

+208
-107
lines changed

10 files changed

+208
-107
lines changed

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use syntax::codemap::Span;
99
#[derive(Clone, Debug)]
1010
pub enum EvalError<'tcx> {
1111
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
12+
NoMirFor(String),
1213
DanglingPointerDeref,
1314
InvalidMemoryAccess,
1415
InvalidFunctionPointer,
@@ -82,6 +83,8 @@ impl<'tcx> Error for EvalError<'tcx> {
8283
"array index out of bounds",
8384
EvalError::Math(..) =>
8485
"mathematical operation failed",
86+
EvalError::NoMirFor(..) =>
87+
"mir not found",
8588
EvalError::InvalidChar(..) =>
8689
"tried to interpret an invalid 32-bit value as a char",
8790
EvalError::OutOfMemory{..} =>
@@ -113,6 +116,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
113116
write!(f, "memory access of {}..{} outside bounds of allocation {} which has size {}",
114117
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
115118
},
119+
EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
116120
EvalError::FunctionPointerTyMismatch(expected, got) =>
117121
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
118122
EvalError::ArrayIndexOutOfBounds(span, len, index) =>

src/interpreter/mod.rs

Lines changed: 109 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -267,25 +267,33 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
267267
ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
268268
}
269269

270-
pub fn load_mir(&self, def_id: DefId) -> CachedMir<'a, 'tcx> {
270+
pub fn load_mir(&self, def_id: DefId) -> EvalResult<'tcx, CachedMir<'a, 'tcx>> {
271+
trace!("load mir {:?}", def_id);
271272
if def_id.is_local() {
272-
CachedMir::Ref(self.mir_map.map.get(&def_id).unwrap())
273+
Ok(CachedMir::Ref(self.mir_map.map.get(&def_id).unwrap()))
273274
} else {
274275
let mut mir_cache = self.mir_cache.borrow_mut();
275276
if let Some(mir) = mir_cache.get(&def_id) {
276-
return CachedMir::Owned(mir.clone());
277+
return Ok(CachedMir::Owned(mir.clone()));
277278
}
278279

279280
let cs = &self.tcx.sess.cstore;
280-
let mir = cs.maybe_get_item_mir(self.tcx, def_id).unwrap_or_else(|| {
281-
panic!("no mir for `{}`", self.tcx.item_path_str(def_id));
282-
});
283-
let cached = Rc::new(mir);
284-
mir_cache.insert(def_id, cached.clone());
285-
CachedMir::Owned(cached)
281+
match cs.maybe_get_item_mir(self.tcx, def_id) {
282+
Some(mir) => {
283+
let cached = Rc::new(mir);
284+
mir_cache.insert(def_id, cached.clone());
285+
Ok(CachedMir::Owned(cached))
286+
},
287+
None => Err(EvalError::NoMirFor(self.tcx.item_path_str(def_id))),
288+
}
286289
}
287290
}
288291

292+
pub fn monomorphize_field_ty(&self, f: ty::FieldDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
293+
let substituted = &f.ty(self.tcx, substs);
294+
self.tcx.normalize_associated_type(&substituted)
295+
}
296+
289297
pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
290298
let substituted = ty.subst(self.tcx, substs);
291299
self.tcx.normalize_associated_type(&substituted)
@@ -519,7 +527,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
519527
.chain(nonnull.offset_after_field.iter().map(|s| s.bytes()));
520528
try!(self.assign_fields(dest, offsets, operands));
521529
} else {
522-
assert_eq!(operands.len(), 0);
530+
for operand in operands {
531+
let operand_ty = self.operand_ty(operand);
532+
assert_eq!(self.type_size(operand_ty), 0);
533+
}
523534
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
524535
let dest = dest.offset(offset.bytes() as isize);
525536
try!(self.memory.write_isize(dest, 0));
@@ -596,56 +607,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
596607
self.memory.write_ptr(dest, ptr)?;
597608
}
598609

599-
Cast(kind, ref operand, dest_ty) => {
610+
Cast(kind, ref operand, cast_ty) => {
611+
debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
600612
use rustc::mir::repr::CastKind::*;
601613
match kind {
602614
Unsize => {
603615
let src = self.eval_operand(operand)?;
604616
let src_ty = self.operand_ty(operand);
605-
let dest_ty = self.monomorphize(dest_ty, self.substs());
606-
// FIXME: cases where dest_ty is not a fat pointer. e.g. Arc<Struct> -> Arc<Trait>
607-
assert!(self.type_is_fat_ptr(dest_ty));
608-
let src_pointee_ty = pointee_type(src_ty).unwrap();
609-
let dest_pointee_ty = pointee_type(dest_ty).unwrap();
610-
611-
// A<Struct> -> A<Trait> conversion
612-
let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(src_pointee_ty, dest_pointee_ty);
613-
614-
match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
615-
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
616-
let ptr = src.read_ptr(&self.memory)?;
617-
self.memory.write_ptr(dest, ptr)?;
618-
let ptr_size = self.memory.pointer_size() as isize;
619-
let dest_extra = dest.offset(ptr_size);
620-
self.memory.write_usize(dest_extra, length as u64)?;
621-
}
622-
(&ty::TyTrait(_), &ty::TyTrait(_)) => {
623-
// For now, upcasts are limited to changes in marker
624-
// traits, and hence never actually require an actual
625-
// change to the vtable.
626-
self.write_value(src, dest, dest_ty)?;
627-
},
628-
(_, &ty::TyTrait(ref data)) => {
629-
let trait_ref = data.principal.with_self_ty(self.tcx, src_pointee_ty);
630-
let trait_ref = self.tcx.erase_regions(&trait_ref);
631-
let vtable = self.get_vtable(trait_ref)?;
632-
let ptr = src.read_ptr(&self.memory)?;
633-
634-
self.memory.write_ptr(dest, ptr)?;
635-
let ptr_size = self.memory.pointer_size() as isize;
636-
let dest_extra = dest.offset(ptr_size);
637-
self.memory.write_ptr(dest_extra, vtable)?;
638-
},
639-
640-
_ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
641-
}
617+
self.unsize_into(src, src_ty, dest, dest_ty)?;
642618
}
643619

644620
Misc => {
645621
let src = self.eval_operand(operand)?;
646622
let src_ty = self.operand_ty(operand);
647-
// FIXME: dest_ty should already be monomorphized
648-
let dest_ty = self.monomorphize(dest_ty, self.substs());
649623
if self.type_is_fat_ptr(src_ty) {
650624
trace!("misc cast: {:?}", src);
651625
let ptr_size = self.memory.pointer_size();
@@ -760,9 +734,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
760734

761735
use rustc::ty::layout::Layout::*;
762736
match *layout {
763-
Univariant { .. } => {
764-
assert_eq!(field_index, 0);
765-
Ok(Size::from_bytes(0))
737+
Univariant { ref variant, .. } => {
738+
Ok(variant.field_offset(field_index))
766739
}
767740
FatPointer { .. } => {
768741
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size();
@@ -1106,16 +1079,91 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11061079
fn substs(&self) -> &'tcx Substs<'tcx> {
11071080
self.frame().substs
11081081
}
1109-
}
11101082

1111-
fn pointee_type(ptr_ty: ty::Ty) -> Option<ty::Ty> {
1112-
match ptr_ty.sty {
1113-
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1114-
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
1115-
ty::TyBox(ty) => {
1116-
Some(ty)
1083+
fn unsize_into(
1084+
&mut self,
1085+
src: Value,
1086+
src_ty: Ty<'tcx>,
1087+
dest: Pointer,
1088+
dest_ty: Ty<'tcx>,
1089+
) -> EvalResult<'tcx, ()> {
1090+
match (&src_ty.sty, &dest_ty.sty) {
1091+
(&ty::TyBox(sty), &ty::TyBox(dty)) |
1092+
(&ty::TyRef(_, ty::TypeAndMut { ty: sty, .. }), &ty::TyRef(_, ty::TypeAndMut { ty: dty, .. })) |
1093+
(&ty::TyRef(_, ty::TypeAndMut { ty: sty, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: dty, .. })) |
1094+
(&ty::TyRawPtr(ty::TypeAndMut { ty: sty, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: dty, .. })) => {
1095+
// A<Struct> -> A<Trait> conversion
1096+
let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);
1097+
1098+
match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1099+
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
1100+
let ptr = src.read_ptr(&self.memory)?;
1101+
self.memory.write_ptr(dest, ptr)?;
1102+
let ptr_size = self.memory.pointer_size() as isize;
1103+
let dest_extra = dest.offset(ptr_size);
1104+
self.memory.write_usize(dest_extra, length as u64)?;
1105+
}
1106+
(&ty::TyTrait(_), &ty::TyTrait(_)) => {
1107+
// For now, upcasts are limited to changes in marker
1108+
// traits, and hence never actually require an actual
1109+
// change to the vtable.
1110+
self.write_value(src, dest, dest_ty)?;
1111+
},
1112+
(_, &ty::TyTrait(ref data)) => {
1113+
let trait_ref = data.principal.with_self_ty(self.tcx, src_pointee_ty);
1114+
let trait_ref = self.tcx.erase_regions(&trait_ref);
1115+
let vtable = self.get_vtable(trait_ref)?;
1116+
let ptr = src.read_ptr(&self.memory)?;
1117+
1118+
self.memory.write_ptr(dest, ptr)?;
1119+
let ptr_size = self.memory.pointer_size() as isize;
1120+
let dest_extra = dest.offset(ptr_size);
1121+
self.memory.write_ptr(dest_extra, vtable)?;
1122+
},
1123+
1124+
_ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
1125+
}
1126+
}
1127+
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => {
1128+
// unsizing of generic struct with pointer fields
1129+
// Example: `Arc<T>` -> `Arc<Trait>`
1130+
// here we need to increase the size of every &T thin ptr field to a fat ptr
1131+
1132+
assert_eq!(def_a, def_b);
1133+
1134+
let src_fields = def_a.variants[0].fields.iter();
1135+
let dst_fields = def_b.variants[0].fields.iter();
1136+
1137+
//let src = adt::MaybeSizedValue::sized(src);
1138+
//let dst = adt::MaybeSizedValue::sized(dst);
1139+
let src_ptr = match src {
1140+
Value::ByRef(ptr) => ptr,
1141+
_ => panic!("expected pointer, got {:?}", src),
1142+
};
1143+
1144+
let iter = src_fields.zip(dst_fields).enumerate();
1145+
for (i, (src_f, dst_f)) in iter {
1146+
let src_fty = self.monomorphize_field_ty(src_f, substs_a);
1147+
let dst_fty = self.monomorphize_field_ty(dst_f, substs_b);
1148+
if self.type_size(dst_fty) == 0 {
1149+
continue;
1150+
}
1151+
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes() as isize;
1152+
let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes() as isize;
1153+
let src_f_ptr = src_ptr.offset(src_field_offset);
1154+
let dst_f_ptr = dest.offset(dst_field_offset);
1155+
if src_fty == dst_fty {
1156+
self.move_(src_f_ptr, dst_f_ptr, src_fty)?;
1157+
} else {
1158+
self.unsize_into(Value::ByRef(src_f_ptr), src_fty, dst_f_ptr, dst_fty)?;
1159+
}
1160+
}
1161+
}
1162+
_ => bug!("unsize_into: invalid conversion: {:?} -> {:?}",
1163+
src_ty,
1164+
dest_ty),
11171165
}
1118-
_ => None,
1166+
Ok(())
11191167
}
11201168
}
11211169

src/interpreter/step.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
125125
if self.ecx.statics.contains_key(&cid) {
126126
return;
127127
}
128-
let mir = self.ecx.load_mir(def_id);
129128
self.try(|this| {
129+
let mir = this.ecx.load_mir(def_id)?;
130130
let ptr = this.ecx.alloc_ret_ptr(mir.return_ty, substs)?;
131131
this.ecx.statics.insert(cid.clone(), ptr);
132132
let cleanup = if immutable && !mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe() {
@@ -200,18 +200,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
200200
if let mir::Lvalue::Static(def_id) = *lvalue {
201201
let substs = subst::Substs::empty(self.ecx.tcx);
202202
let span = self.span;
203-
let node_item = self.ecx.tcx.map.get_if_local(def_id).expect("static not found");
204-
if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
205-
if let hir::ItemStatic(_, m, _) = *node {
206-
self.global_item(def_id, substs, span, m == hir::MutImmutable);
207-
return;
203+
if let Some(node_item) = self.ecx.tcx.map.get_if_local(def_id) {
204+
if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
205+
if let hir::ItemStatic(_, m, _) = *node {
206+
self.global_item(def_id, substs, span, m == hir::MutImmutable);
207+
return;
208+
} else {
209+
bug!("static def id doesn't point to static");
210+
}
208211
} else {
209-
bug!("static def id doesn't point to static");
212+
bug!("static def id doesn't point to item");
210213
}
211214
} else {
212-
bug!("static def id doesn't point to item");
215+
let def = self.ecx.tcx.sess.cstore.describe_def(def_id).expect("static not found");
216+
if let hir::def::Def::Static(_, mutable) = def {
217+
self.global_item(def_id, substs, span, !mutable);
218+
} else {
219+
bug!("static found but isn't a static: {:?}", def);
220+
}
213221
}
214-
self.global_item(def_id, substs, span, false);
215222
}
216223
}
217224
}

src/interpreter/terminator/mod.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use rustc::hir::def_id::DefId;
2-
use rustc::middle::const_val::ConstVal;
32
use rustc::mir::repr as mir;
43
use rustc::traits::{self, Reveal};
54
use rustc::ty::fold::TypeFoldable;
@@ -45,26 +44,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
4544
SwitchInt { ref discr, ref values, ref targets, .. } => {
4645
let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
4746
let discr_ty = self.lvalue_ty(discr);
48-
let discr_size = self
49-
.type_layout(discr_ty)
50-
.size(&self.tcx.data_layout)
51-
.bytes() as usize;
52-
let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
53-
if let ty::TyChar = discr_ty.sty {
54-
if ::std::char::from_u32(discr_val as u32).is_none() {
55-
return Err(EvalError::InvalidChar(discr_val as u64));
56-
}
57-
}
47+
let discr_val = self.read_value(discr_ptr, discr_ty)?;
48+
let discr_prim = self.value_to_primval(discr_val, discr_ty)?;
5849

5950
// Branch to the `otherwise` case by default, if no match is found.
6051
let mut target_block = targets[targets.len() - 1];
6152

6253
for (index, const_val) in values.iter().enumerate() {
63-
let val = match const_val {
64-
&ConstVal::Integral(i) => i.to_u64_unchecked(),
65-
_ => bug!("TerminatorKind::SwitchInt branch constant was not an integer"),
66-
};
67-
if discr_val == val {
54+
let val = self.const_to_value(const_val)?;
55+
let prim = self.value_to_primval(val, discr_ty)?;
56+
if discr_prim == prim {
6857
target_block = targets[index];
6958
break;
7059
}
@@ -195,7 +184,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
195184
(def_id, substs)
196185
};
197186

198-
let mir = self.load_mir(resolved_def_id);
187+
let mir = self.load_mir(resolved_def_id)?;
199188
let (return_ptr, return_to_block) = match destination {
200189
Some((ptr, block)) => (Some(ptr), StackPopCleanup::Goto(block)),
201190
None => (None, StackPopCleanup::None),

src/interpreter/vtable.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,35 +112,25 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
112112

113113
self.tcx.populate_implementations_for_trait_if_necessary(trait_id);
114114

115-
let trait_item_def_ids = self.tcx.trait_item_def_ids(trait_id);
115+
let trait_item_def_ids = self.tcx.impl_or_trait_items(trait_id);
116116
trait_item_def_ids
117117
.iter()
118118

119119
// Filter out non-method items.
120-
.filter_map(|item_def_id| {
121-
match *item_def_id {
122-
ty::MethodTraitItemId(def_id) => Some(def_id),
123-
_ => None,
124-
}
125-
})
126-
127-
// Now produce pointers for each remaining method. If the
128-
// method could never be called from this object, just supply
129-
// null.
130-
.map(|trait_method_def_id| {
120+
.filter_map(|&trait_method_def_id| {
121+
let trait_method_type = match self.tcx.impl_or_trait_item(trait_method_def_id) {
122+
ty::MethodTraitItem(trait_method_type) => trait_method_type,
123+
_ => return None,
124+
};
131125
debug!("get_vtable_methods: trait_method_def_id={:?}",
132126
trait_method_def_id);
133127

134-
let trait_method_type = match self.tcx.impl_or_trait_item(trait_method_def_id) {
135-
ty::MethodTraitItem(m) => m,
136-
_ => bug!("should be a method, not other assoc item"),
137-
};
138128
let name = trait_method_type.name;
139129

140130
// Some methods cannot be called on an object; skip those.
141131
if !self.tcx.is_vtable_safe_method(trait_id, &trait_method_type) {
142132
debug!("get_vtable_methods: not vtable safe");
143-
return None;
133+
return Some(None);
144134
}
145135

146136
debug!("get_vtable_methods: trait_method_type={:?}",
@@ -167,11 +157,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
167157
let predicates = mth.method.predicates.predicates.subst(self.tcx, mth.substs);
168158
if !self.normalize_and_test_predicates(predicates) {
169159
debug!("get_vtable_methods: predicates do not hold");
170-
return None;
160+
return Some(None);
171161
}
172162
}
173163

174-
Some(mth)
164+
Some(Some(mth))
175165
})
176166
.collect()
177167
}

0 commit comments

Comments
 (0)