1
Fork 0

tag/niche terminology cleanup

This commit is contained in:
Ralf Jung 2020-05-23 13:22:45 +02:00
parent 91fb72a8a9
commit f7d745f33d
10 changed files with 167 additions and 169 deletions

View file

@ -1,4 +1,4 @@
use self::EnumDiscriminantInfo::*;
use self::EnumTagInfo::*;
use self::MemberDescriptionFactory::*;
use self::RecursiveTypeDescription::*;
@ -40,7 +40,7 @@ use rustc_middle::{bug, span_bug};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::{Interner, Symbol};
use rustc_span::{self, SourceFile, SourceFileHash, Span};
use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names(
struct EnumMemberDescriptionFactory<'ll, 'tcx> {
enum_type: Ty<'tcx>,
layout: TyAndLayout<'tcx>,
discriminant_type_metadata: Option<&'ll DIType>,
tag_type_metadata: Option<&'ll DIType>,
containing_scope: &'ll DIScope,
span: Span,
}
@ -1385,7 +1385,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
self.layout,
variant_info,
NoDiscriminant,
NoTag,
self_metadata,
self.span,
);
@ -1409,19 +1409,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
}]
}
Variants::Multiple {
discr_kind: DiscriminantKind::Tag,
discr_index,
tag_encoding: TagEncoding::Direct,
tag_field,
ref variants,
..
} => {
let discriminant_info = if fallback {
RegularDiscriminant {
discr_field: Field::from(discr_index),
discr_type_metadata: self.discriminant_type_metadata.unwrap(),
let tag_info = if fallback {
RegularTag {
tag_field: Field::from(tag_field),
tag_type_metadata: self.tag_type_metadata.unwrap(),
}
} else {
// This doesn't matter in this case.
NoDiscriminant
NoTag
};
variants
.iter_enumerated()
@ -1432,7 +1432,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
variant,
variant_info,
discriminant_info,
tag_info,
self_metadata,
self.span,
);
@ -1467,11 +1467,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
.collect()
}
Variants::Multiple {
discr_kind:
DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant },
ref discr,
tag_encoding:
TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
ref tag,
ref variants,
discr_index,
tag_field,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
@ -1480,7 +1480,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
variant,
variant_info_for(dataful_variant),
OptimizedDiscriminant,
OptimizedTag,
self.containing_scope,
self.span,
);
@ -1524,8 +1524,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
&mut name,
self.layout,
self.layout.fields.offset(discr_index),
self.layout.field(cx, discr_index).size,
self.layout.fields.offset(tag_field),
self.layout.field(cx, tag_field).size,
);
variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
name.push_str(variant_name);
@ -1552,7 +1552,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
variant,
variant_info,
OptimizedDiscriminant,
OptimizedTag,
self_metadata,
self.span,
);
@ -1573,7 +1573,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
let value = (i.as_u32() as u128)
.wrapping_sub(niche_variants.start().as_u32() as u128)
.wrapping_add(niche_start);
let value = truncate(value, discr.value.size(cx));
let value = truncate(value, tag.value.size(cx));
// NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected.
@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> {
/// Cloned from the `layout::Struct` describing the variant.
offsets: Vec<Size>,
args: Vec<(String, Ty<'tcx>)>,
discriminant_type_metadata: Option<&'ll DIType>,
tag_type_metadata: Option<&'ll DIType>,
span: Span,
}
@ -1617,7 +1617,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
MemberDescription {
name: name.to_string(),
type_metadata: if use_enum_fallback(cx) {
match self.discriminant_type_metadata {
match self.tag_type_metadata {
// Discriminant is always the first field of our variant
// when using the enum fallback.
Some(metadata) if i == 0 => metadata,
@ -1638,10 +1638,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
}
#[derive(Copy, Clone)]
enum EnumDiscriminantInfo<'ll> {
RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType },
OptimizedDiscriminant,
NoDiscriminant,
enum EnumTagInfo<'ll> {
RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
OptimizedTag,
NoTag,
}
#[derive(Copy, Clone)]
@ -1706,7 +1706,7 @@ fn describe_enum_variant(
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
discriminant_info: EnumDiscriminantInfo<'ll>,
discriminant_info: EnumTagInfo<'ll>,
containing_scope: &'ll DIScope,
span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
@ -1722,12 +1722,12 @@ fn describe_enum_variant(
let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
RegularDiscriminant { discr_field, .. } => {
RegularTag { tag_field, .. } => {
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
let offset = enum_layout.fields.offset(discr_field.as_usize());
let offset = enum_layout.fields.offset(tag_field.as_usize());
let args =
("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty);
("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
(Some(offset), Some(args))
}
_ => (None, None),
@ -1757,8 +1757,8 @@ fn describe_enum_variant(
let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
offsets,
args,
discriminant_type_metadata: match discriminant_info {
RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata),
tag_type_metadata: match discriminant_info {
RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
_ => None,
},
span,
@ -1880,18 +1880,18 @@ fn prepare_enum_metadata(
if let (
&Abi::Scalar(_),
&Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. },
&Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
) = (&layout.abi, &layout.variants)
{
return FinalMetadata(discriminant_type_metadata(discr.value));
return FinalMetadata(discriminant_type_metadata(tag.value));
}
if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants {
Variants::Single { .. }
| Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None,
Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => {
Some(discriminant_type_metadata(discr.value))
| Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
Some(discriminant_type_metadata(tag.value))
}
};
@ -1927,7 +1927,7 @@ fn prepare_enum_metadata(
EnumMDF(EnumMemberDescriptionFactory {
enum_type,
layout,
discriminant_type_metadata,
tag_type_metadata: discriminant_type_metadata,
containing_scope,
span,
}),
@ -1943,16 +1943,13 @@ fn prepare_enum_metadata(
Variants::Single { .. } => None,
Variants::Multiple {
discr_kind: DiscriminantKind::Niche { .. },
ref discr,
discr_index,
..
tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
} => {
// Find the integer type of the correct size.
let size = discr.value.size(cx);
let align = discr.value.align(cx);
let size = tag.value.size(cx);
let align = tag.value.align(cx);
let discr_type = match discr.value {
let tag_type = match tag.value {
Int(t, _) => t,
F32 => Integer::I32,
F64 => Integer::I64,
@ -1960,7 +1957,7 @@ fn prepare_enum_metadata(
}
.to_ty(cx.tcx, false);
let discr_metadata = basic_type_metadata(cx, discr_type);
let tag_metadata = basic_type_metadata(cx, tag_type);
unsafe {
Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
@ -1971,17 +1968,15 @@ fn prepare_enum_metadata(
UNKNOWN_LINE_NUMBER,
size.bits(),
align.abi.bits() as u32,
layout.fields.offset(discr_index).bits(),
layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial,
discr_metadata,
tag_metadata,
))
}
}
Variants::Multiple {
discr_kind: DiscriminantKind::Tag, ref discr, discr_index, ..
} => {
let discr_type = discr.value.to_ty(cx.tcx);
Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
let discr_type = tag.value.to_ty(cx.tcx);
let (size, align) = cx.size_and_align_of(discr_type);
let discr_metadata = basic_type_metadata(cx, discr_type);
@ -1995,7 +1990,7 @@ fn prepare_enum_metadata(
UNKNOWN_LINE_NUMBER,
size.bits(),
align.bits() as u32,
layout.fields.offset(discr_index).bits(),
layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial,
discr_metadata,
))
@ -2081,7 +2076,7 @@ fn prepare_enum_metadata(
EnumMDF(EnumMemberDescriptionFactory {
enum_type,
layout,
discriminant_type_metadata: None,
tag_type_metadata: None,
containing_scope,
span,
}),

View file

@ -10,7 +10,7 @@ use rustc_middle::mir;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int};
use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
#[derive(Copy, Clone, Debug)]
@ -199,7 +199,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
if self.layout.abi.is_uninhabited() {
return bx.cx().const_undef(cast_to);
}
let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
Variants::Single { index } => {
let discr_val = self
.layout
@ -208,33 +208,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
.map_or(index.as_u32() as u128, |discr| discr.val);
return bx.cx().const_uint_big(cast_to, discr_val);
}
Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
(discr, discr_kind, discr_index)
Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
(tag, tag_encoding, tag_field)
}
};
// Read the tag/niche-encoded discriminant from memory.
let encoded_discr = self.project_field(bx, discr_index);
let encoded_discr = bx.load_operand(encoded_discr);
let tag = self.project_field(bx, tag_field);
let tag = bx.load_operand(tag);
// Decode the discriminant (specifically if it's niche-encoded).
match *discr_kind {
DiscriminantKind::Tag => {
let signed = match discr_scalar.value {
match *tag_encoding {
TagEncoding::Direct => {
let signed = match tag_scalar.value {
// We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because
// then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
Int(_, signed) => !discr_scalar.is_bool() && signed,
Int(_, signed) => !tag_scalar.is_bool() && signed,
_ => false,
};
bx.intcast(encoded_discr.immediate(), cast_to, signed)
bx.intcast(tag.immediate(), cast_to, signed)
}
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Rebase from niche values to discriminants, and check
// whether the result is in range for the niche variants.
let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout);
let encoded_discr = encoded_discr.immediate();
let niche_llty = bx.cx().immediate_backend_type(tag.layout);
let tag = tag.immediate();
// We first compute the "relative discriminant" (wrt `niche_variants`),
// that is, if `n = niche_variants.end() - niche_variants.start()`,
@ -248,9 +248,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
let relative_discr = if niche_start == 0 {
// Avoid subtracting `0`, which wouldn't work for pointers.
// FIXME(eddyb) check the actual primitive type here.
encoded_discr
tag
} else {
bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start))
bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
};
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
let is_niche = {
@ -312,8 +312,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
Variants::Single { index } => {
assert_eq!(index, variant_index);
}
Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => {
let ptr = self.project_field(bx, discr_index);
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
let ptr = self.project_field(bx, tag_field);
let to =
self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
bx.store(
@ -323,9 +323,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
);
}
Variants::Multiple {
discr_kind:
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
discr_index,
tag_encoding:
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
tag_field,
..
} => {
if variant_index != dataful_variant {
@ -339,7 +339,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
}
let niche = self.project_field(bx, discr_index);
let niche = self.project_field(bx, tag_field);
let niche_llty = bx.cx().immediate_backend_type(niche.layout);
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
let niche_value = (niche_value as u128).wrapping_add(niche_start);

View file

@ -16,7 +16,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc_span::source_map;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants};
use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
use rustc_target::spec::abi::Abi;
use log::debug;
@ -1036,15 +1036,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
};
let (variants, tag) = match layout.variants {
Variants::Multiple {
discr_kind: DiscriminantKind::Tag,
ref discr,
tag_encoding: TagEncoding::Direct,
ref tag,
ref variants,
..
} => (variants, discr),
} => (variants, tag),
_ => return,
};
let discr_size = tag.value.size(&cx.tcx).bytes();
let tag_size = tag.value.size(&cx.tcx).bytes();
debug!(
"enum `{}` is {} bytes large with layout:\n{:#?}",
@ -1058,8 +1058,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
.iter()
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant.
let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
// Subtract the size of the enum tag.
let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
bytes

View file

@ -975,13 +975,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
return Ok(tcx.intern_layout(Layout {
variants: Variants::Multiple {
discr: niche_scalar,
discr_kind: DiscriminantKind::Niche {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
dataful_variant: i,
niche_variants,
niche_start,
},
discr_index: 0,
tag_field: 0,
variants: st,
},
fields: FieldsShape::Arbitrary {
@ -1217,9 +1217,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
tcx.intern_layout(Layout {
variants: Variants::Multiple {
discr: tag,
discr_kind: DiscriminantKind::Tag,
discr_index: 0,
tag,
tag_encoding: TagEncoding::Direct,
tag_field: 0,
variants: layout_variants,
},
fields: FieldsShape::Arbitrary {
@ -1400,15 +1400,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Build a prefix layout, including "promoting" all ineligible
// locals as part of the prefix. We compute the layout of all of
// these fields at once to get optimal packing.
let discr_index = substs.as_generator().prefix_tys().count();
let tag_index = substs.as_generator().prefix_tys().count();
// `info.variant_fields` already accounts for the reserved variants, so no need to add them.
let max_discr = (info.variant_fields.len() - 1) as u128;
let discr_int = Integer::fit_unsigned(max_discr);
let discr_int_ty = discr_int.to_ty(tcx, false);
let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone()));
let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout };
let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
let promoted_layouts = ineligible_locals
.iter()
@ -1419,7 +1419,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
.as_generator()
.prefix_tys()
.map(|ty| self.layout_of(ty))
.chain(iter::once(Ok(discr_layout)))
.chain(iter::once(Ok(tag_layout)))
.chain(promoted_layouts)
.collect::<Result<Vec<_>, _>>()?;
let prefix = self.univariant_uninterned(
@ -1442,7 +1442,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
// "outer" and "promoted" fields respectively.
let b_start = (discr_index + 1) as u32;
let b_start = (tag_index + 1) as u32;
let offsets_b = offsets.split_off(b_start as usize);
let offsets_a = offsets;
@ -1559,9 +1559,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let layout = tcx.intern_layout(Layout {
variants: Variants::Multiple {
discr,
discr_kind: DiscriminantKind::Tag,
discr_index,
tag: tag,
tag_encoding: TagEncoding::Direct,
tag_field: tag_index,
variants,
},
fields: outer_fields,
@ -1681,7 +1681,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}
Variants::Multiple { ref discr, ref discr_kind, .. } => {
Variants::Multiple { ref tag, ref tag_encoding, .. } => {
debug!(
"print-type-size `{:#?}` adt general variants def {}",
layout.ty,
@ -1703,8 +1703,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
record(
adt_kind.into(),
adt_packed,
match discr_kind {
DiscriminantKind::Tag => Some(discr.value.size(self)),
match tag_encoding {
TagEncoding::Direct => Some(tag.value.size(self)),
_ => None,
},
variant_infos,
@ -2029,11 +2029,11 @@ where
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
let tcx = cx.tcx();
let discr_layout = |discr: &Scalar| -> C::TyAndLayout {
let layout = Layout::scalar(cx, discr.clone());
let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
let layout = Layout::scalar(cx, tag.clone());
MaybeResult::from(Ok(TyAndLayout {
layout: tcx.intern_layout(layout),
ty: discr.value.to_ty(tcx),
ty: tag.value.to_ty(tcx),
}))
};
@ -2110,9 +2110,9 @@ where
.unwrap()
.nth(i)
.unwrap(),
Variants::Multiple { ref discr, discr_index, .. } => {
if i == discr_index {
return discr_layout(discr);
Variants::Multiple { ref tag, tag_field, .. } => {
if i == tag_field {
return tag_layout(tag);
}
substs.as_generator().prefix_tys().nth(i).unwrap()
}
@ -2129,9 +2129,9 @@ where
Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
// Discriminant field for enums (where applicable).
Variants::Multiple { ref discr, .. } => {
Variants::Multiple { ref tag, .. } => {
assert_eq!(i, 0);
return discr_layout(discr);
return tag_layout(tag);
}
}
}
@ -2208,10 +2208,10 @@ where
// using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers).
Variants::Multiple {
discr_kind: DiscriminantKind::Niche { dataful_variant, .. },
discr_index,
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
tag_field,
..
} if this.fields.offset(discr_index) == offset => {
} if this.fields.offset(tag_field) == offset => {
Some(this.for_variant(cx, dataful_variant))
}
_ => Some(this),

View file

@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
use rustc_middle::ty::Ty;
use rustc_middle::{mir, ty};
use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
use rustc_target::abi::{Abi, TagEncoding, HasDataLayout, LayoutOf, Size};
use rustc_target::abi::{VariantIdx, Variants};
use super::{
@ -587,7 +587,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
op: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
trace!("read_discriminant_value {:#?}", op.layout);
// Get type and layout of the discriminant.
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
trace!("discriminant type: {:?}", discr_layout.ty);
@ -596,10 +595,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// This is not to be confused with its "variant index", which is just determining its position in the
// declared list of variants -- they can differ with explicitly assigned discriminants.
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
// straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
// Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
// rather confusing.
let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
Variants::Single { index } => {
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
Some(discr) => {
@ -615,8 +612,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
return Ok((discr, index));
}
Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
(discr, discr_kind, discr_index)
Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
(tag, tag_encoding, tag_field)
}
};
@ -633,21 +630,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
// Read tag and sanity-check `tag_layout`.
let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
let tag_val = tag_val.to_scalar()?;
trace!("tag value: {:?}", tag_val);
// Figure out which discriminant and variant this corresponds to.
Ok(match *tag_kind {
DiscriminantKind::Tag => {
Ok(match *tag_encoding {
TagEncoding::Direct => {
let tag_bits = self
.force_bits(tag_val, tag_layout.size)
.map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
// Cast bits from tag layout to discriminant layout.
let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants.
let index = match op.layout.ty.kind {
ty::Adt(adt, _) => {
@ -663,9 +660,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
.ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
// Return the cast value, and the index.
(discr_val_cast, index.0)
(discr_val, index.0)
}
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Compute the variant this niche value/"tag" corresponds to. With niche layout,
// discriminant (encoded in niche/tag) and variant index are the same.
let variants_start = niche_variants.start().as_u32();

View file

@ -9,7 +9,7 @@ use rustc_macros::HashStable;
use rustc_middle::mir;
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape};
use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{
@ -1031,7 +1031,8 @@ where
MPlaceTy { mplace, layout }
}
pub fn write_discriminant_index(
/// Writes the discriminant of the given variant.
pub fn write_discriminant(
&mut self,
variant_index: VariantIdx,
dest: PlaceTy<'tcx, M::PointerTag>,
@ -1047,9 +1048,9 @@ where
assert_eq!(index, variant_index);
}
Variants::Multiple {
discr_kind: DiscriminantKind::Tag,
discr: ref discr_layout,
discr_index,
tag_encoding: TagEncoding::Direct,
tag: ref tag_layout,
tag_field,
..
} => {
// No need to validate that the discriminant here because the
@ -1061,17 +1062,17 @@ where
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
let size = discr_layout.value.size(self);
let discr_val = truncate(discr_val, size);
let size = tag_layout.value.size(self);
let tag_val = truncate(discr_val, size);
let discr_dest = self.place_field(dest, discr_index)?;
self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
let tag_dest = self.place_field(dest, tag_field)?;
self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
}
Variants::Multiple {
discr_kind:
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
discr: ref discr_layout,
discr_index,
tag_encoding:
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
tag: ref tag_layout,
tag_field,
..
} => {
// No need to validate that the discriminant here because the
@ -1084,19 +1085,19 @@ where
.checked_sub(variants_start)
.expect("overflow computing relative variant idx");
// We need to use machine arithmetic when taking into account `niche_start`:
// discr_val = variant_index_relative + niche_start_val
let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
// tag_val = variant_index_relative + niche_start_val
let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
let variant_index_relative_val =
ImmTy::from_uint(variant_index_relative, discr_layout);
let discr_val = self.binary_op(
ImmTy::from_uint(variant_index_relative, tag_layout);
let tag_val = self.binary_op(
mir::BinOp::Add,
variant_index_relative_val,
niche_start_val,
)?;
// Write result.
let niche_dest = self.place_field(dest, discr_index)?;
self.write_immediate(*discr_val, niche_dest)?;
let niche_dest = self.place_field(dest, tag_field)?;
self.write_immediate(*tag_val, niche_dest)?;
}
}
}

View file

@ -89,7 +89,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?;
self.write_discriminant_index(*variant_index, dest)?;
self.write_discriminant(*variant_index, dest)?;
}
// Mark locals as alive
@ -174,7 +174,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Aggregate(ref kind, ref operands) => {
let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
self.write_discriminant_index(variant_index, dest)?;
self.write_discriminant(variant_index, dest)?;
if adt_def.is_enum() {
(self.place_downcast(dest, variant_index)?, active_field_index)
} else {

View file

@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
// First, check if we are projecting to a variant.
match layout.variants {
Variants::Multiple { discr_index, .. } => {
if discr_index == field {
Variants::Multiple { tag_field, .. } => {
if tag_field == field {
return match layout.ty.kind {
ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
ty::Generator(..) => PathElem::GeneratorTag,

View file

@ -809,25 +809,30 @@ pub enum Variants {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },
/// Enum-likes with more than one inhabited variant: for each case there is
/// a struct, and they all have space reserved for the discriminant.
/// For enums this is the sole field of the layout.
/// Enum-likes with more than one inhabited variant: each variant comes with
/// a *discriminant* (usually the same as the variant index but the user can
/// assign explicit discriminant values). That discriminant is encoded
/// as a *tag* on the machine. The layout of each variant is
/// a struct, and they all have space reserved for the tag.
/// For enums, the tag is the sole field of the layout.
Multiple {
discr: Scalar,
discr_kind: DiscriminantKind,
discr_index: usize,
tag: Scalar,
tag_encoding: TagEncoding,
tag_field: usize,
variants: IndexVec<VariantIdx, Layout>,
},
}
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum DiscriminantKind {
/// Integer tag holding the discriminant value itself.
Tag,
pub enum TagEncoding {
/// The tag directly stores the discriminant, but possibly with a smaller layout
/// (so converting the tag to the discriminant can require sign extension).
Direct,
/// Niche (values invalid for a type) encoding the discriminant:
/// the variant `dataful_variant` contains a niche at an arbitrary
/// offset (field `discr_index` of the enum), which for a variant with
/// Discriminant and variant index coincide.
/// The variant `dataful_variant` contains a niche at an arbitrary
/// offset (field `tag_field` of the enum), which for a variant with
/// discriminant `d` is set to
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
///

View file

@ -10,15 +10,15 @@ error: layout_of(E) = Layout {
],
},
variants: Multiple {
discr: Scalar {
tag: Scalar {
value: Int(
I32,
false,
),
valid_range: 0..=0,
},
discr_kind: Tag,
discr_index: 0,
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
@ -202,15 +202,15 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
],
},
variants: Multiple {
discr: Scalar {
tag: Scalar {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
discr_kind: Tag,
discr_index: 0,
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
fields: Arbitrary {