|
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