Skip to content

Commit 98295e9

Browse files
committed
use more traditional walk_array/visit_array instead of the handle_array hook
1 parent aea61e3 commit 98295e9

File tree

2 files changed

+73
-71
lines changed

2 files changed

+73
-71
lines changed

src/librustc_mir/interpret/validity.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -212,19 +212,19 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
212212
// Perform operation
213213
self.push_aggregate_field_path_elem(op.layout, field);
214214
self.op = val;
215-
self.visit(ectx)?;
215+
self.visit_value(ectx)?;
216216
// Undo changes
217217
self.path.truncate(path_len);
218218
self.op = op;
219219
Ok(())
220220
}
221221

222222
#[inline]
223-
fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
223+
fn visit_value(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
224224
-> EvalResult<'tcx>
225225
{
226226
// Translate enum discriminant errors to something nicer.
227-
match ectx.walk_value(self) {
227+
match self.walk_value(ectx) {
228228
Ok(()) => Ok(()),
229229
Err(err) => match err.kind {
230230
EvalErrorKind::InvalidDiscriminant(val) =>
@@ -479,15 +479,14 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
479479
}
480480
}
481481

482-
fn handle_array(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>)
483-
-> EvalResult<'tcx, bool>
482+
fn visit_array(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
483+
-> EvalResult<'tcx>
484484
{
485-
Ok(match self.op.layout.ty.sty {
485+
match self.op.layout.ty.sty {
486486
ty::Str => {
487487
let mplace = self.op.to_mem_place(); // strings are never immediate
488488
try_validation!(ectx.read_str(mplace),
489489
"uninitialized or non-UTF-8 data in str", self.path);
490-
true
491490
}
492491
ty::Array(tys, ..) | ty::Slice(tys) if {
493492
// This optimization applies only for integer and floating point types
@@ -526,7 +525,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
526525
/*allow_ptr_and_undef*/!self.const_mode,
527526
) {
528527
// In the happy case, we needn't check anything else.
529-
Ok(()) => true, // handled these arrays
528+
Ok(()) => {},
530529
// Some error happened, try to provide a more detailed description.
531530
Err(err) => {
532531
// For some errors we might be able to provide extra information
@@ -548,8 +547,11 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
548547
}
549548
}
550549
}
551-
_ => false, // not handled
552-
})
550+
_ => {
551+
self.walk_array(ectx)? // default handler
552+
}
553+
}
554+
Ok(())
553555
}
554556
}
555557

@@ -580,6 +582,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
580582
};
581583

582584
// Run it
583-
visitor.visit(self)
585+
visitor.visit_value(self)
584586
}
585587
}

src/librustc_mir/interpret/visitor.rs

Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -178,77 +178,91 @@ pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug +
178178
self.value().layout()
179179
}
180180

181-
// Replace the value by `val`, which must be the `field`th field of `self`, then call
182-
// `visit_value` and then un-do everything that might have happened to the visitor state.
183-
// The point of this is that some visitors keep a stack of fields that we projected below,
184-
// and this lets us avoid copying that stack; instead they will pop the stack after
185-
// executing `visit_value`.
186-
fn visit_field(
187-
&mut self,
188-
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
189-
val: Self::V,
190-
field: usize,
191-
) -> EvalResult<'tcx>;
192-
193-
// A chance for the visitor to do special (different or more efficient) handling for some
194-
// array types. Return `true` if the value was handled and we should return.
181+
// Recursie actions, ready to be overloaded.
182+
/// Visit the current value, dispatching as appropriate to more speicalized visitors.
195183
#[inline]
196-
fn handle_array(&mut self, _ectx: &EvalContext<'a, 'mir, 'tcx, M>)
197-
-> EvalResult<'tcx, bool>
184+
fn visit_value(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
185+
-> EvalResult<'tcx>
198186
{
199-
Ok(false)
187+
self.walk_value(ectx)
200188
}
201-
202-
// Execute visitor on the current value. Used for recursing.
189+
/// Visit the current value as an array.
203190
#[inline]
204-
fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
191+
fn visit_array(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
205192
-> EvalResult<'tcx>
206193
{
207-
ectx.walk_value(self)
194+
self.walk_array(ectx)
208195
}
196+
/// Called each time we recurse down to a field of the value, to (a) let
197+
/// the visitor change its internal state (recording the new current value),
198+
/// and (b) let the visitor track the "stack" of fields that we descended below.
199+
fn visit_field(
200+
&mut self,
201+
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
202+
val: Self::V,
203+
field: usize,
204+
) -> EvalResult<'tcx>;
209205

210-
// Actions on the leaves.
206+
// Actions on the leaves, ready to be overloaded.
207+
#[inline]
211208
fn visit_uninhabited(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
212209
-> EvalResult<'tcx>
213210
{ Ok(()) }
211+
#[inline]
214212
fn visit_scalar(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, _layout: &layout::Scalar)
215213
-> EvalResult<'tcx>
216214
{ Ok(()) }
215+
#[inline]
217216
fn visit_primitive(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
218217
-> EvalResult<'tcx>
219218
{ Ok(()) }
220-
}
221219

222-
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
223-
pub fn walk_value<V: ValueVisitor<'a, 'mir, 'tcx, M>>(
224-
&mut self,
225-
v: &mut V,
226-
) -> EvalResult<'tcx> {
227-
trace!("walk_value: {:?}", v);
220+
// Default recursors. Not meant to be overloaded.
221+
fn walk_array(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
222+
-> EvalResult<'tcx>
223+
{
224+
// Let's get an mplace first.
225+
let mplace = if self.layout().is_zst() {
226+
// it's a ZST, the memory content cannot matter
227+
MPlaceTy::dangling(self.layout(), ectx)
228+
} else {
229+
// non-ZST array/slice/str cannot be immediate
230+
self.value().to_mem_place(ectx)?
231+
};
232+
// Now iterate over it.
233+
for (i, field) in ectx.mplace_array_fields(mplace)?.enumerate() {
234+
self.visit_field(ectx, Value::from_mem_place(field?), i)?;
235+
}
236+
Ok(())
237+
}
238+
fn walk_value(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
239+
-> EvalResult<'tcx>
240+
{
241+
trace!("walk_value: {:?}", self);
228242

229243
// If this is a multi-variant layout, we have find the right one and proceed with that.
230244
// (No benefit from making this recursion, but it is equivalent to that.)
231-
match v.layout().variants {
245+
match self.layout().variants {
232246
layout::Variants::NicheFilling { .. } |
233247
layout::Variants::Tagged { .. } => {
234-
let (inner, idx) = v.value().project_downcast(self)?;
248+
let (inner, idx) = self.value().project_downcast(ectx)?;
235249
trace!("variant layout: {:#?}", inner.layout());
236250
// recurse with the inner type
237-
return v.visit_field(self, inner, idx);
251+
return self.visit_field(ectx, inner, idx);
238252
}
239253
layout::Variants::Single { .. } => {}
240254
}
241255

242256
// Even for single variants, we might be able to get a more refined type:
243257
// If it is a trait object, switch to the actual type that was used to create it.
244-
match v.layout().ty.sty {
258+
match self.layout().ty.sty {
245259
ty::Dynamic(..) => {
246260
// immediate trait objects are not a thing
247-
let dest = v.value().to_mem_place(self)?;
248-
let inner = self.unpack_dyn_trait(dest)?.1;
261+
let dest = self.value().to_mem_place(ectx)?;
262+
let inner = ectx.unpack_dyn_trait(dest)?.1;
249263
trace!("dyn object layout: {:#?}", inner.layout);
250264
// recurse with the inner type
251-
return v.visit_field(self, Value::from_mem_place(inner), 0);
265+
return self.visit_field(ectx, Value::from_mem_place(inner), 0);
252266
},
253267
_ => {},
254268
};
@@ -260,12 +274,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
260274
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
261275
// scalars, we do the same check on every "level" (e.g. first we check
262276
// MyNewtype and then the scalar in there).
263-
match v.layout().abi {
277+
match self.layout().abi {
264278
layout::Abi::Uninhabited => {
265-
v.visit_uninhabited(self)?;
279+
self.visit_uninhabited(ectx)?;
266280
}
267281
layout::Abi::Scalar(ref layout) => {
268-
v.visit_scalar(self, layout)?;
282+
self.visit_scalar(ectx, layout)?;
269283
}
270284
// FIXME: Should we do something for ScalarPair? Vector?
271285
_ => {}
@@ -276,17 +290,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
276290
// so we check them separately and before aggregate handling.
277291
// It is CRITICAL that we get this check right, or we might be
278292
// validating the wrong thing!
279-
let primitive = match v.layout().fields {
293+
let primitive = match self.layout().fields {
280294
// Primitives appear as Union with 0 fields -- except for Boxes and fat pointers.
281295
layout::FieldPlacement::Union(0) => true,
282-
_ => v.layout().ty.builtin_deref(true).is_some(),
296+
_ => self.layout().ty.builtin_deref(true).is_some(),
283297
};
284298
if primitive {
285-
return v.visit_primitive(self);
299+
return self.visit_primitive(ectx);
286300
}
287301

288302
// Proceed into the fields.
289-
match v.layout().fields {
303+
match self.layout().fields {
290304
layout::FieldPlacement::Union(fields) => {
291305
// Empty unions are not accepted by rustc. That's great, it means we can
292306
// use that as an unambiguous signal for detecting primitives. Make sure
@@ -298,26 +312,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
298312
},
299313
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
300314
for i in 0..offsets.len() {
301-
let val = v.value().project_field(self, i as u64)?;
302-
v.visit_field(self, val, i)?;
315+
let val = self.value().project_field(ectx, i as u64)?;
316+
self.visit_field(ectx, val, i)?;
303317
}
304318
},
305319
layout::FieldPlacement::Array { .. } => {
306-
if !v.handle_array(self)? {
307-
// We still have to work!
308-
// Let's get an mplace first.
309-
let mplace = if v.layout().is_zst() {
310-
// it's a ZST, the memory content cannot matter
311-
MPlaceTy::dangling(v.layout(), self)
312-
} else {
313-
// non-ZST array/slice/str cannot be immediate
314-
v.value().to_mem_place(self)?
315-
};
316-
// Now iterate over it.
317-
for (i, field) in self.mplace_array_fields(mplace)?.enumerate() {
318-
v.visit_field(self, Value::from_mem_place(field?), i)?;
319-
}
320-
}
320+
self.visit_array(ectx)?;
321321
}
322322
}
323323
Ok(())

0 commit comments

Comments
 (0)