Skip to content

Commit 42d3eda

Browse files
authored
Merge pull request rust-lang#220 from oli-obk/undo_single_field_opt
Remove the `field` field from `Lvalue::Local`
2 parents 6edca30 + a724a39 commit 42d3eda

File tree

5 files changed

+37
-119
lines changed

5 files changed

+37
-119
lines changed

src/eval_context.rs

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,12 +1003,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10031003
lvalue: Lvalue<'tcx>,
10041004
) -> EvalResult<'tcx, Lvalue<'tcx>> {
10051005
let new_lvalue = match lvalue {
1006-
Lvalue::Local { frame, local, field } => {
1006+
Lvalue::Local { frame, local } => {
10071007
// -1 since we don't store the return value
10081008
match self.stack[frame].locals[local.index() - 1] {
10091009
None => return Err(EvalError::DeadLocal),
10101010
Some(Value::ByRef(ptr)) => {
1011-
assert!(field.is_none());
10121011
Lvalue::from_ptr(ptr)
10131012
},
10141013
Some(val) => {
@@ -1018,12 +1017,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10181017
let ptr = self.alloc_ptr_with_substs(ty, substs)?;
10191018
self.stack[frame].locals[local.index() - 1] = Some(Value::ByRef(ptr)); // it stays live
10201019
self.write_value_to_ptr(val, PrimVal::Ptr(ptr), ty)?;
1021-
let lval = Lvalue::from_ptr(ptr);
1022-
if let Some((field, field_ty)) = field {
1023-
self.lvalue_field(lval, field, ty, field_ty)?
1024-
} else {
1025-
lval
1026-
}
1020+
Lvalue::from_ptr(ptr)
10271021
}
10281022
}
10291023
}
@@ -1110,11 +1104,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11101104
self.write_value_to_ptr(src_val, ptr, dest_ty)
11111105
}
11121106

1113-
Lvalue::Local { frame, local, field } => {
1114-
let dest = self.stack[frame].get_local(local, field.map(|(i, _)| i))?;
1107+
Lvalue::Local { frame, local } => {
1108+
let dest = self.stack[frame].get_local(local)?;
11151109
self.write_value_possibly_by_val(
11161110
src_val,
1117-
|this, val| this.stack[frame].set_local(local, field.map(|(i, _)| i), val),
1111+
|this, val| this.stack[frame].set_local(local, val),
11181112
dest,
11191113
dest_ty,
11201114
)
@@ -1353,7 +1347,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13531347
I128 => 16,
13541348
Is => self.memory.pointer_size(),
13551349
};
1356-
PrimVal::from_i128(self.memory.read_int(ptr, size)?)
1350+
// if we cast a ptr to an isize, reading it back into a primval shouldn't panic
1351+
// Due to read_ptr ignoring the sign, we need to jump around some hoops
1352+
match self.memory.read_int(ptr, size) {
1353+
Err(EvalError::ReadPointerAsBytes) if size == self.memory.pointer_size() => self.memory.read_ptr(ptr)?,
1354+
other => PrimVal::from_i128(other?),
1355+
}
13571356
}
13581357

13591358
ty::TyUint(uint_ty) => {
@@ -1366,7 +1365,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13661365
U128 => 16,
13671366
Us => self.memory.pointer_size(),
13681367
};
1369-
PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
1368+
if size == self.memory.pointer_size() {
1369+
// if we cast a ptr to an usize, reading it back into a primval shouldn't panic
1370+
self.memory.read_ptr(ptr)?
1371+
} else {
1372+
PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
1373+
}
13701374
}
13711375

13721376
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
@@ -1518,19 +1522,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15181522

15191523
pub(super) fn dump_local(&self, lvalue: Lvalue<'tcx>) {
15201524
// Debug output
1521-
if let Lvalue::Local { frame, local, field } = lvalue {
1525+
if let Lvalue::Local { frame, local } = lvalue {
15221526
let mut allocs = Vec::new();
15231527
let mut msg = format!("{:?}", local);
1524-
if let Some((field, _)) = field {
1525-
write!(msg, ".{}", field).unwrap();
1526-
}
15271528
let last_frame = self.stack.len() - 1;
15281529
if frame != last_frame {
15291530
write!(msg, " ({} frames up)", last_frame - frame).unwrap();
15301531
}
15311532
write!(msg, ":").unwrap();
15321533

1533-
match self.stack[frame].get_local(local, field.map(|(i, _)| i)) {
1534+
match self.stack[frame].get_local(local) {
15341535
Err(EvalError::DeadLocal) => {
15351536
write!(msg, " is dead").unwrap();
15361537
}
@@ -1575,14 +1576,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15751576
&mut self,
15761577
frame: usize,
15771578
local: mir::Local,
1578-
field: Option<usize>,
15791579
f: F,
15801580
) -> EvalResult<'tcx>
15811581
where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
15821582
{
1583-
let val = self.stack[frame].get_local(local, field)?;
1583+
let val = self.stack[frame].get_local(local)?;
15841584
let new_val = f(self, val)?;
1585-
self.stack[frame].set_local(local, field, new_val)?;
1585+
self.stack[frame].set_local(local, new_val)?;
15861586
// FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
15871587
// if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
15881588
// self.memory.deallocate(ptr)?;
@@ -1598,59 +1598,20 @@ impl<'tcx> Frame<'tcx> {
15981598
_ => false,
15991599
}
16001600
}
1601-
pub fn get_local(&self, local: mir::Local, field: Option<usize>) -> EvalResult<'tcx, Value> {
1601+
pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
16021602
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1603-
if let Some(field) = field {
1604-
Ok(match self.locals[local.index() - 1] {
1605-
None => return Err(EvalError::DeadLocal),
1606-
Some(Value::ByRef(_)) => bug!("can't have lvalue fields for ByRef"),
1607-
Some(val @ Value::ByVal(_)) => {
1608-
assert_eq!(field, 0);
1609-
val
1610-
},
1611-
Some(Value::ByValPair(a, b)) => {
1612-
match field {
1613-
0 => Value::ByVal(a),
1614-
1 => Value::ByVal(b),
1615-
_ => bug!("ByValPair has only two fields, tried to access {}", field),
1616-
}
1617-
},
1618-
})
1619-
} else {
1620-
self.locals[local.index() - 1].ok_or(EvalError::DeadLocal)
1621-
}
1603+
self.locals[local.index() - 1].ok_or(EvalError::DeadLocal)
16221604
}
16231605

1624-
fn set_local(&mut self, local: mir::Local, field: Option<usize>, value: Value) -> EvalResult<'tcx> {
1606+
fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
16251607
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1626-
if let Some(field) = field {
1627-
match self.locals[local.index() - 1] {
1628-
None => return Err(EvalError::DeadLocal),
1629-
Some(Value::ByRef(_)) => bug!("can't have lvalue fields for ByRef"),
1630-
Some(Value::ByVal(_)) => {
1631-
assert_eq!(field, 0);
1632-
self.set_local(local, None, value)?;
1633-
},
1634-
Some(Value::ByValPair(a, b)) => {
1635-
let prim = match value {
1636-
Value::ByRef(_) => bug!("can't set ValPair field to ByRef"),
1637-
Value::ByVal(val) => val,
1638-
Value::ByValPair(_, _) => bug!("can't set ValPair field to ValPair"),
1639-
};
1640-
match field {
1641-
0 => self.set_local(local, None, Value::ByValPair(prim, b))?,
1642-
1 => self.set_local(local, None, Value::ByValPair(a, prim))?,
1643-
_ => bug!("ByValPair has only two fields, tried to access {}", field),
1644-
}
1645-
},
1646-
}
1647-
} else {
1648-
match self.locals[local.index() - 1] {
1649-
None => return Err(EvalError::DeadLocal),
1650-
Some(ref mut local) => { *local = value; }
1608+
match self.locals[local.index() - 1] {
1609+
None => Err(EvalError::DeadLocal),
1610+
Some(ref mut local) => {
1611+
*local = value;
1612+
Ok(())
16511613
}
16521614
}
1653-
return Ok(());
16541615
}
16551616

16561617
pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {

src/lvalue.rs

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ pub enum Lvalue<'tcx> {
2424
Local {
2525
frame: usize,
2626
local: mir::Local,
27-
/// Optionally, this lvalue can point to a field of the stack value
28-
field: Option<(usize, Ty<'tcx>)>,
2927
},
3028

3129
/// An lvalue referring to a global
@@ -141,8 +139,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
141139
assert_eq!(extra, LvalueExtra::None);
142140
Ok(Value::ByRef(ptr.to_ptr()?))
143141
}
144-
Lvalue::Local { frame, local, field } => {
145-
self.stack[frame].get_local(local, field.map(|(i, _)| i))
142+
Lvalue::Local { frame, local } => {
143+
self.stack[frame].get_local(local)
146144
}
147145
Lvalue::Global(cid) => {
148146
Ok(self.globals.get(&cid).expect("global not cached").value)
@@ -154,7 +152,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
154152
use rustc::mir::Lvalue::*;
155153
let lvalue = match *mir_lvalue {
156154
Local(mir::RETURN_POINTER) => self.frame().return_lvalue,
157-
Local(local) => Lvalue::Local { frame: self.stack.len() - 1, local, field: None },
155+
Local(local) => Lvalue::Local { frame: self.stack.len() - 1, local },
158156

159157
Static(ref static_) => {
160158
let instance = ty::Instance::mono(self.tcx, static_.def_id);
@@ -235,48 +233,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
235233
_ => bug!("field access on non-product type: {:?}", base_layout),
236234
};
237235

238-
let (base_ptr, base_extra) = match base {
239-
Lvalue::Ptr { ptr, extra } => (ptr, extra),
240-
Lvalue::Local { frame, local, field } => match self.stack[frame].get_local(local, field.map(|(i, _)| i))? {
241-
Value::ByRef(ptr) => {
242-
assert!(field.is_none(), "local can't be ByRef and have a field offset");
243-
(PrimVal::Ptr(ptr), LvalueExtra::None)
244-
},
245-
Value::ByVal(PrimVal::Undef) => {
246-
// FIXME: allocate in fewer cases
247-
if self.ty_to_primval_kind(base_ty).is_ok() {
248-
return Ok(base);
249-
} else {
250-
(PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
251-
}
252-
},
253-
Value::ByVal(_) => {
254-
if self.get_field_count(base_ty)? == 1 {
255-
assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0");
256-
return Ok(base);
257-
}
258-
// this branch is taken when a union creates a large ByVal which is then
259-
// accessed as a struct with multiple small fields
260-
(PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
261-
},
262-
Value::ByValPair(_, _) => {
263-
let field_count = self.get_field_count(base_ty)?;
264-
if field_count == 1 {
265-
assert_eq!(field_index, 0, "{:?} has only one field", base_ty);
266-
return Ok(base);
267-
}
268-
assert_eq!(field_count, 2);
269-
assert!(field_index < 2);
270-
return Ok(Lvalue::Local {
271-
frame,
272-
local,
273-
field: Some((field_index, field_ty)),
274-
});
275-
},
276-
},
277-
// FIXME: do for globals what we did for locals
278-
Lvalue::Global(_) => self.force_allocation(base)?.to_ptr_and_extra(),
279-
};
236+
let (base_ptr, base_extra) = self.force_allocation(base)?.to_ptr_and_extra();
280237

281238
let offset = match base_extra {
282239
LvalueExtra::Vtable(tab) => {

src/step.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
112112
// Mark locals as dead or alive.
113113
StorageLive(ref lvalue) | StorageDead(ref lvalue)=> {
114114
let (frame, local) = match self.eval_lvalue(lvalue)? {
115-
Lvalue::Local{ frame, local, field: None } if self.stack.len() == frame+1 => (frame, local),
115+
Lvalue::Local{ frame, local } if self.stack.len() == frame+1 => (frame, local),
116116
_ => return Err(EvalError::Unimplemented("Storage annotations must refer to locals of the topmost stack frame.".to_owned())) // FIXME maybe this should get its own error type
117117
};
118118
let old_val = match stmt.kind {

src/terminator/intrinsic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
269269
Ok(zero_val)
270270
};
271271
match dest {
272-
Lvalue::Local { frame, local, field } => self.modify_local(frame, local, field.map(|(i, _)| i), init)?,
272+
Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
273273
Lvalue::Ptr { ptr, extra: LvalueExtra::None } => self.memory.write_repeat(ptr.to_ptr()?, 0, size)?,
274274
Lvalue::Ptr { .. } => bug!("init intrinsic tried to write to fat ptr target"),
275275
Lvalue::Global(cid) => self.modify_global(cid, init)?,
@@ -419,7 +419,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
419419
}
420420
};
421421
match dest {
422-
Lvalue::Local { frame, local, field } => self.modify_local(frame, local, field.map(|(i, _)| i), uninit)?,
422+
Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?,
423423
Lvalue::Ptr { ptr, extra: LvalueExtra::None } =>
424424
self.memory.mark_definedness(ptr, size, false)?,
425425
Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat ptr target"),

tests/compile-fail/pointer_byte_read_1.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ fn main() {
33
let y = &x;
44
let z = &y as *const &i32 as *const usize;
55
let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once
6-
let _ = ptr_bytes == 15; //~ ERROR: tried to access part of a pointer value as raw bytes
6+
let _ = ptr_bytes % 432; //~ ERROR: tried to access part of a pointer value as raw bytes
77
}

0 commit comments

Comments
 (0)