diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 84aa5b6756660ceb4f224c37324e1ec6fe7d3668..38170949734a9389942ea588c05704b019e74779 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -13,7 +13,7 @@ use std::ops::RangeInclusive; use syntax_pos::symbol::Symbol; -use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf}; +use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc::mir::interpret::{ @@ -74,6 +74,7 @@ #[derive(Copy, Clone, Debug)] pub enum PathElem { Field(Symbol), + Variant(Symbol), ClosureVar(Symbol), ArrayElem(usize), TupleElem(usize), @@ -107,6 +108,7 @@ fn path_format(path: &Vec) -> String { for elem in path.iter() { match elem { Field(name) => write!(out, ".{}", name), + Variant(name) => write!(out, ".", name), ClosureVar(name) => write!(out, ".", name), TupleElem(idx) => write!(out, ".{}", idx), ArrayElem(idx) => write!(out, "[{}]", idx), @@ -192,9 +194,11 @@ fn push_aggregate_field_path_elem( 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) + _ => { + // Enums have no fields other than their tag + assert_eq!(field, 0); + PathElem::Tag + } } } @@ -241,6 +245,24 @@ fn visit_field( Ok(()) } + #[inline] + fn visit_variant( + &mut self, + old_op: OpTy<'tcx, M::PointerTag>, + variant_id: VariantIdx, + new_op: OpTy<'tcx, M::PointerTag> + ) -> EvalResult<'tcx> { + // Remember the old state + let path_len = self.path.len(); + // Perform operation + let name = old_op.layout.ty.ty_adt_def().unwrap().variants[variant_id].name; + self.path.push(PathElem::Variant(name)); + self.visit_value(new_op)?; + // Undo changes + self.path.truncate(path_len); + Ok(()) + } + #[inline] fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 392e27918092f45ec2b4a2093b99a7de4542b51b..4a470456432533fb1a13f4835508fe07a709385c 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -1,7 +1,7 @@ //! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound //! types until we arrive at the leaves, with custom handling for primitive types. -use rustc::ty::layout::{self, TyLayout}; +use rustc::ty::layout::{self, TyLayout, VariantIdx}; use rustc::ty; use rustc::mir::interpret::{ EvalResult, @@ -32,7 +32,7 @@ fn to_op( fn project_downcast( self, ecx: &EvalContext<'a, 'mir, 'tcx, M>, - variant: usize, + variant: VariantIdx, ) -> EvalResult<'tcx, Self>; /// Project to the n-th field. @@ -70,7 +70,7 @@ fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { fn project_downcast( self, ecx: &EvalContext<'a, 'mir, 'tcx, M>, - variant: usize, + variant: VariantIdx, ) -> EvalResult<'tcx, Self> { ecx.operand_downcast(self, variant) } @@ -109,7 +109,7 @@ fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { fn project_downcast( self, ecx: &EvalContext<'a, 'mir, 'tcx, M>, - variant: usize, + variant: VariantIdx, ) -> EvalResult<'tcx, Self> { ecx.mplace_downcast(self, variant) } @@ -171,6 +171,16 @@ fn visit_field( self.visit_value(new_val) } + #[inline(always)] + fn visit_variant( + &mut self, + _old_val: Self::V, + _variant: VariantIdx, + new_val: Self::V, + ) -> EvalResult<'tcx> { + self.visit_value(new_val) + } + /// Called whenever we reach a value with uninhabited layout. /// Recursing to fields will *always* continue after this! This is not meant to control /// whether and how we descend recursively/ into the scalar's fields if there are any, @@ -221,7 +231,7 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> let inner = v.project_downcast(self.ecx(), idx)?; trace!("walk_value: variant layout: {:#?}", inner.layout()); // recurse with the inner type - return self.visit_field(v, idx, inner); + return self.visit_variant(v, idx, inner); } layout::Variants::Single { .. } => {} } diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 804c9643d8ae30f93dc42fae1187258f12a57bda..d36e96b08174a125cfb6f30bcca976d39587ef58 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:61:1 | LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something less or equal to 1114111 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior