diff options
| author | Ralf Jung <post@ralfj.de> | 2018-11-01 13:53:21 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2018-11-05 09:17:48 +0100 |
| commit | 6d24b37a70de0afc2b145aff72964162ec8a4291 (patch) | |
| tree | 199d68820b027e763b6767420006807aa269091d /src/librustc_mir/interpret | |
| parent | b0f1b1a73ee1c5be48d3a288eff50a46b773a9df (diff) | |
| download | rust-6d24b37a70de0afc2b145aff72964162ec8a4291.tar.gz rust-6d24b37a70de0afc2b145aff72964162ec8a4291.zip | |
let the Value handle enum projections, so the visitor does not have to care
Diffstat (limited to 'src/librustc_mir/interpret')
| -rw-r--r-- | src/librustc_mir/interpret/validity.rs | 39 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/visitor.rs | 47 |
2 files changed, 56 insertions, 30 deletions
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 2d977d10944..f7ba92c40eb 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -173,11 +173,15 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> { // enums ty::Adt(def, ..) if def.is_enum() => { - let variant = match layout.variants { - layout::Variants::Single { index } => &def.variants[index], - _ => bug!("aggregate_field_path_elem: got enum but not in a specific variant"), - }; - PathElem::Field(variant.fields[field].ident.name) + // we might be projecting *to* a variant, or to a field *in*a variant. + match layout.variants { + layout::Variants::Single { index } => + // Inside a variant + PathElem::Field(def.variants[index].fields[field].ident.name), + _ => + // To a variant + PathElem::Field(def.variants[field].name) + } } // other ADTs @@ -226,30 +230,21 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Ok(()) } - fn downcast_enum(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>) + #[inline] + fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>) -> EvalResult<'tcx> { - let variant = match ectx.read_discriminant(self.op) { - Ok(res) => res.1, - Err(err) => return match err.kind { + // Translate enum discriminant errors to something nicer. + match ectx.walk_value(self) { + Ok(()) => Ok(()), + Err(err) => match err.kind { EvalErrorKind::InvalidDiscriminant(val) => validation_failure!( format!("invalid enum discriminant {}", val), self.path ), - _ => - validation_failure!( - format!("non-integer enum discriminant"), self.path - ), + _ => Err(err), } - }; - // Put the variant projection onto the path, as a field - self.path.push(PathElem::Field(self.op.layout.ty - .ty_adt_def() - .unwrap() - .variants[variant].name)); - // Proceed with this variant - self.op = ectx.operand_downcast(self.op, variant)?; - Ok(()) + } } fn visit_primitive(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>) diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 96e76ffd972..863eeb3b250 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -30,6 +30,13 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy // Create this from an `MPlaceTy`. fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self; + // Read the current enum discriminant, and downcast to that. Also return the + // variant index. + fn project_downcast( + self, + ectx: &EvalContext<'a, 'mir, 'tcx, M> + ) -> EvalResult<'tcx, (Self, usize)>; + // Project to the n-th field. fn project_field( self, @@ -61,6 +68,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> } #[inline(always)] + fn project_downcast( + self, + ectx: &EvalContext<'a, 'mir, 'tcx, M> + ) -> EvalResult<'tcx, (Self, usize)> { + let idx = ectx.read_discriminant(self)?.1; + Ok((ectx.operand_downcast(self, idx)?, idx)) + } + + #[inline(always)] fn project_field( self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, @@ -91,6 +107,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> } #[inline(always)] + fn project_downcast( + self, + ectx: &EvalContext<'a, 'mir, 'tcx, M> + ) -> EvalResult<'tcx, (Self, usize)> { + let idx = ectx.read_discriminant(self.into())?.1; + Ok((ectx.mplace_downcast(self, idx)?, idx)) + } + + #[inline(always)] fn project_field( self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, @@ -121,6 +146,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> } #[inline(always)] + fn project_downcast( + self, + ectx: &EvalContext<'a, 'mir, 'tcx, M> + ) -> EvalResult<'tcx, (Self, usize)> { + let idx = ectx.read_discriminant(ectx.place_to_op(self)?)?.1; + Ok((ectx.place_downcast(self, idx)?, idx)) + } + + #[inline(always)] fn project_field( self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, @@ -155,12 +189,6 @@ pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug + field: usize, ) -> EvalResult<'tcx>; - // This is an enum, downcast it to whatever the current variant is. - // (We do this here and not in `Value` to keep error handling - // under control of th visitor.) - fn downcast_enum(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>) - -> EvalResult<'tcx>; - // A chance for the visitor to do special (different or more efficient) handling for some // array types. Return `true` if the value was handled and we should return. #[inline] @@ -202,8 +230,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> match v.layout().variants { layout::Variants::NicheFilling { .. } | layout::Variants::Tagged { .. } => { - v.downcast_enum(self)?; - trace!("variant layout: {:#?}", v.layout()); + let (inner, idx) = v.value().project_downcast(self)?; + trace!("variant layout: {:#?}", inner.layout()); + // recurse with the inner type + return v.visit_field(self, inner, idx); } layout::Variants::Single { .. } => {} } @@ -215,6 +245,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // immediate trait objects are not a thing let dest = v.value().force_allocation(self)?; let inner = self.unpack_dyn_trait(dest)?.1; + trace!("dyn object layout: {:#?}", inner.layout); // recurse with the inner type return v.visit_field(self, Value::from_mem_place(inner), 0); }, |
