Skip to content

Commit 14a674c

Browse files
committed
interpret: read_discriminant: only return VariantIdx
1 parent a2bcafa commit 14a674c

File tree

7 files changed

+49
-35
lines changed

7 files changed

+49
-35
lines changed

compiler/rustc_const_eval/src/const_eval/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>(
101101
return None;
102102
}
103103
ty::Adt(def, _) => {
104-
let variant = ecx.read_discriminant(&op).ok()?.1;
104+
let variant = ecx.read_discriminant(&op).ok()?;
105105
let down = ecx.project_downcast(&op, variant).ok()?;
106106
(def.variants()[variant].fields.len(), Some(variant), down)
107107
}

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
130130
bug!("uninhabited types should have errored and never gotten converted to valtree")
131131
}
132132

133-
let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else {
133+
let Ok(variant) = ecx.read_discriminant(&place.into()) else {
134134
return Err(ValTreeCreationError::Other);
135135
};
136136
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)

compiler/rustc_const_eval/src/interpret/discriminant.rs

+39-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Functions for reading and writing discriminants of multi-variant layouts (enums and generators).
22
3-
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
3+
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
44
use rustc_middle::{mir, ty};
55
use rustc_target::abi::{self, TagEncoding};
66
use rustc_target::abi::{VariantIdx, Variants};
@@ -93,7 +93,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9393
pub fn read_discriminant(
9494
&self,
9595
op: &OpTy<'tcx, M::Provenance>,
96-
) -> InterpResult<'tcx, (Scalar<M::Provenance>, VariantIdx)> {
96+
) -> InterpResult<'tcx, VariantIdx> {
9797
trace!("read_discriminant_value {:#?}", op.layout);
9898
// Get type and layout of the discriminant.
9999
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
@@ -106,30 +106,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
106106
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
107107
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
108108
Variants::Single { index } => {
109-
// Hilariously, `Single` is used even for 0-variant enums.
110-
// (See https://github.com/rust-lang/rust/issues/89765).
111-
if matches!(op.layout.ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) {
112-
throw_ub!(UninhabitedEnumVariantRead(index))
113-
}
114-
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
115-
Some(discr) => {
116-
// This type actually has discriminants.
117-
assert_eq!(discr.ty, discr_layout.ty);
118-
Scalar::from_uint(discr.val, discr_layout.size)
109+
// Do some extra checks on enums.
110+
if op.layout.ty.is_enum() {
111+
// Hilariously, `Single` is used even for 0-variant enums.
112+
// (See https://github.com/rust-lang/rust/issues/89765).
113+
if matches!(op.layout.ty.kind(), ty::Adt(def, ..) if def.variants().is_empty())
114+
{
115+
throw_ub!(UninhabitedEnumVariantRead(index))
119116
}
120-
None => {
121-
// On a type without actual discriminants, variant is 0.
122-
assert_eq!(index.as_u32(), 0);
123-
Scalar::from_uint(index.as_u32(), discr_layout.size)
117+
// For consisteny with `write_discriminant`, and to make sure that
118+
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
119+
// for uninhabited variants.
120+
if op.layout.for_variant(self, index).abi.is_uninhabited() {
121+
throw_ub!(UninhabitedEnumVariantRead(index))
124122
}
125-
};
126-
// For consisteny with `write_discriminant`, and to make sure that
127-
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
128-
// for uninhabited variants.
129-
if op.layout.ty.is_enum() && op.layout.for_variant(self, index).abi.is_uninhabited() {
130-
throw_ub!(UninhabitedEnumVariantRead(index))
131123
}
132-
return Ok((discr, index));
124+
return Ok(index);
133125
}
134126
Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
135127
(tag, tag_encoding, tag_field)
@@ -155,7 +147,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
155147
trace!("tag value: {}", tag_val);
156148

157149
// Figure out which discriminant and variant this corresponds to.
158-
let (discr, index) = match *tag_encoding {
150+
let index = match *tag_encoding {
159151
TagEncoding::Direct => {
160152
let scalar = tag_val.to_scalar();
161153
// Generate a specific error if `tag_val` is not an integer.
@@ -183,7 +175,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
183175
}
184176
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
185177
// Return the cast value, and the index.
186-
(discr_val, index.0)
178+
index.0
187179
}
188180
TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
189181
let tag_val = tag_val.to_scalar();
@@ -241,13 +233,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
241233
// Compute the size of the scalar we need to return.
242234
// No need to cast, because the variant index directly serves as discriminant and is
243235
// encoded in the tag.
244-
(Scalar::from_uint(variant.as_u32(), discr_layout.size), variant)
236+
variant
245237
}
246238
};
247239
// For consisteny with `write_discriminant`, and to make sure that `project_downcast` cannot fail due to strange layouts, we declare immediate UB for uninhabited variants.
248240
if op.layout.for_variant(self, index).abi.is_uninhabited() {
249241
throw_ub!(UninhabitedEnumVariantRead(index))
250242
}
251-
Ok((discr, index))
243+
Ok(index)
244+
}
245+
246+
pub fn discriminant_for_variant(
247+
&self,
248+
layout: TyAndLayout<'tcx>,
249+
variant: VariantIdx,
250+
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
251+
let discr_layout = self.layout_of(layout.ty.discriminant_ty(*self.tcx))?;
252+
Ok(match layout.ty.discriminant_for_variant(*self.tcx, variant) {
253+
Some(discr) => {
254+
// This type actually has discriminants.
255+
assert_eq!(discr.ty, discr_layout.ty);
256+
Scalar::from_uint(discr.val, discr_layout.size)
257+
}
258+
None => {
259+
// On a type without actual discriminants, variant is 0.
260+
assert_eq!(variant.as_u32(), 0);
261+
Scalar::from_uint(variant.as_u32(), discr_layout.size)
262+
}
263+
})
252264
}
253265
}

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
226226
}
227227
sym::discriminant_value => {
228228
let place = self.deref_operand(&args[0])?;
229-
let discr_val = self.read_discriminant(&place.into())?.0;
230-
self.write_scalar(discr_val, dest)?;
229+
let variant = self.read_discriminant(&place.into())?;
230+
let discr = self.discriminant_for_variant(place.layout, variant)?;
231+
self.write_scalar(discr, dest)?;
231232
}
232233
sym::exact_div => {
233234
let l = self.read_immediate(&args[0])?;

compiler/rustc_const_eval/src/interpret/step.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
302302

303303
Discriminant(place) => {
304304
let op = self.eval_place_to_op(place, None)?;
305-
let discr_val = self.read_discriminant(&op)?.0;
306-
self.write_scalar(discr_val, &dest)?;
305+
let variant = self.read_discriminant(&op)?;
306+
let discr = self.discriminant_for_variant(op.layout, variant)?;
307+
self.write_scalar(discr, &dest)?;
307308
}
308309
}
309310

compiler/rustc_const_eval/src/interpret/validity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
657657
) -> InterpResult<'tcx, VariantIdx> {
658658
self.with_elem(PathElem::EnumTag, move |this| {
659659
Ok(try_validation!(
660-
this.ecx.read_discriminant(op).map(|(_, idx)| idx),
660+
this.ecx.read_discriminant(op),
661661
this.path,
662662
InvalidTag(val) => InvalidEnumTag {
663663
value: format!("{val:x}"),

compiler/rustc_const_eval/src/interpret/visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
2323
/// `read_discriminant` can be hooked for better error messages.
2424
#[inline(always)]
2525
fn read_discriminant(&mut self, v: &Self::V) -> InterpResult<'tcx, VariantIdx> {
26-
Ok(self.ecx().read_discriminant(&v.to_op(self.ecx())?)?.1)
26+
Ok(self.ecx().read_discriminant(&v.to_op(self.ecx())?)?)
2727
}
2828

2929
/// This function provides the chance to reorder the order in which fields are visited for

0 commit comments

Comments
 (0)