Skip to content

Commit ec40255

Browse files
committed
Rewrite place workflow in rustc_mir/interpret
1 parent 2cd7680 commit ec40255

File tree

1 file changed

+53
-38
lines changed

1 file changed

+53
-38
lines changed

src/librustc_mir/interpret/place.rs

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc::mir;
2+
use rustc::mir::tcx::PlaceTy;
23
use rustc::ty::{self, Ty, TyCtxt};
34
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
45
use rustc_data_structures::indexed_vec::Idx;
@@ -101,28 +102,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
101102
&self,
102103
place: &mir::Place<'tcx>,
103104
) -> EvalResult<'tcx, Option<Value>> {
104-
use rustc::mir::PlaceBase::*;
105-
let mut result = match place.base {
106-
Local(local) => {
107-
if local == mir::RETURN_PLACE {
108-
// Might allow this in the future, right now there's no way to do this from Rust code anyway
109-
err!(ReadFromReturnPointer)
110-
} else {
111-
// Directly reading a local will always succeed
112-
self.frame().locals[local].access().map(Some)
113-
}
114-
},
115-
// No fast path for statics. Reading from statics is rare and would require another
116-
// Machine function to handle differently in miri.
117-
Promoted(_) | Static(_) => Ok(None),
118-
};
119-
if !place.elems.is_empty() {
105+
let mut result = self.try_read_place_base(&place.base)?;
106+
let mut base_ty = place.base.ty(self.mir());
107+
let mut base_layout = self.layout_of(base_ty)?;
108+
if !place.has_no_projection() {
120109
for elem in place.elems.iter() {
121-
result = self.try_read_place_projection(place, elem);
110+
result = self.try_read_place_projection(result, elem, base_layout)?;
111+
112+
base_ty = PlaceTy::from(base_ty)
113+
.projection_ty(*self.tcx, elem).to_ty(*self.tcx);
114+
base_layout = self.layout_of(base_ty)?;
122115
}
123116
}
124117

125-
result
118+
Ok(result)
126119
}
127120

128121
pub fn read_field(
@@ -165,27 +158,47 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
165158
Ok((value, field))
166159
}
167160

161+
fn try_read_place_base(
162+
&self,
163+
place_base: &mir::PlaceBase<'tcx>,
164+
) -> EvalResult<'tcx, Option<Value>> {
165+
use rustc::mir::PlaceBase::*;
166+
match place_base {
167+
Local(local) => {
168+
if *local == mir::RETURN_PLACE {
169+
// Might allow this in the future, right now there's no way to do this from Rust code anyway
170+
err!(ReadFromReturnPointer)
171+
} else {
172+
// Directly reading a local will always succeed
173+
self.frame().locals[*local].access().map(Some)
174+
}
175+
},
176+
// No fast path for statics. Reading from statics is rare and would require another
177+
// Machine function to handle differently in miri.
178+
Promoted(_) | Static(_) => Ok(None),
179+
}
180+
}
181+
168182
fn try_read_place_projection(
169183
&self,
170-
base_place: &mir::Place<'tcx>,
184+
base: Option<Value>,
171185
proj: &mir::PlaceElem<'tcx>,
186+
base_layout: TyLayout<'tcx>,
172187
) -> EvalResult<'tcx, Option<Value>> {
173188
use rustc::mir::ProjectionElem::*;
174-
let base = match self.try_read_place(base_place)? {
175-
Some(base) => base,
176-
None => return Ok(None),
177-
};
178-
let base_ty = self.place_ty(base_place);
179-
let base_layout = self.layout_of(base_ty)?;
180-
match proj {
181-
Field(field, _) => Ok(Some(self.read_field(base, None, *field, base_layout)?.0)),
182-
// The NullablePointer cases should work fine, need to take care for normal enums
183-
Downcast(..) |
184-
Subslice { .. } |
185-
// reading index 0 or index 1 from a ByVal or ByVal pair could be optimized
186-
ConstantIndex { .. } | Index(_) |
187-
// No way to optimize this projection any better than the normal place path
188-
Deref => Ok(None),
189+
if let Some(base) = base {
190+
match proj {
191+
Field(field, _) => Ok(Some(self.read_field(base, None, *field, base_layout)?.0)),
192+
// The NullablePointer cases should work fine, need to take care for normal enums
193+
Downcast(..) |
194+
Subslice { .. } |
195+
// reading index 0 or index 1 from a ByVal or ByVal pair could be optimized
196+
ConstantIndex { .. } | Index(_) |
197+
// No way to optimize this projection any better than the normal place path
198+
Deref => Ok(None),
199+
}
200+
} else {
201+
return Ok(None)
189202
}
190203
}
191204

@@ -257,11 +270,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
257270
}
258271
};
259272

260-
if !mir_place.elems.is_empty() {
261-
let ty = self.place_ty(mir_place);
262-
let place1 = self.eval_place(mir_place)?;
273+
if !mir_place.has_no_projection() {
274+
let mut ty = mir_place.base.ty(self.mir());
263275
for elem in mir_place.elems.iter() {
264-
place = self.eval_place_projection(place1, ty, elem)?;
276+
ty = self.monomorphize(ty, self.substs());
277+
place = self.eval_place_projection(place, ty, elem)?;
278+
ty = PlaceTy::from(ty)
279+
.projection_ty(*self.tcx, elem).to_ty(*self.tcx);
265280
}
266281
}
267282

0 commit comments

Comments
 (0)