|
1 | 1 | use rustc::mir;
|
| 2 | +use rustc::mir::tcx::PlaceTy; |
2 | 3 | use rustc::ty::{self, Ty, TyCtxt};
|
3 | 4 | use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
|
4 | 5 | use rustc_data_structures::indexed_vec::Idx;
|
@@ -101,28 +102,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
101 | 102 | &self,
|
102 | 103 | place: &mir::Place<'tcx>,
|
103 | 104 | ) -> 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() { |
120 | 109 | 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)?; |
122 | 115 | }
|
123 | 116 | }
|
124 | 117 |
|
125 |
| - result |
| 118 | + Ok(result) |
126 | 119 | }
|
127 | 120 |
|
128 | 121 | pub fn read_field(
|
@@ -165,27 +158,47 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
165 | 158 | Ok((value, field))
|
166 | 159 | }
|
167 | 160 |
|
| 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 | + |
168 | 182 | fn try_read_place_projection(
|
169 | 183 | &self,
|
170 |
| - base_place: &mir::Place<'tcx>, |
| 184 | + base: Option<Value>, |
171 | 185 | proj: &mir::PlaceElem<'tcx>,
|
| 186 | + base_layout: TyLayout<'tcx>, |
172 | 187 | ) -> EvalResult<'tcx, Option<Value>> {
|
173 | 188 | 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) |
189 | 202 | }
|
190 | 203 | }
|
191 | 204 |
|
@@ -257,11 +270,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
257 | 270 | }
|
258 | 271 | };
|
259 | 272 |
|
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()); |
263 | 275 | 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); |
265 | 280 | }
|
266 | 281 | }
|
267 | 282 |
|
|
0 commit comments