未验证 提交 5e7eec2e 编写于 作者: R Ralf Jung 提交者: GitHub

Rollup merge of #72497 - RalfJung:tag-term, r=oli-obk

tag/niche terminology cleanup

The term "discriminant" was used in two ways throughout the compiler:
* every enum variant has a corresponding discriminant, that can be given explicitly with `Variant = N`.
* that discriminant is then encoded in memory to store which variant is active -- but this encoded form of the discriminant was also often called "discriminant", even though it is conceptually quite different (e.g., it can be smaller in size, or even use niche-filling).

After discussion with @EddyB, this renames the second term to "tag". The way the tag is encoded can be either `TagEncoding::Direct` (formerly `DiscriminantKind::Tag`) or `TagEncoding::Niche` (formerly `DiscrimianntKind::Niche`).

This finally resolves some long-standing confusion I had about the handling of variant indices and discriminants, which surfaced in https://github.com/rust-lang/rust/pull/72419.

(There is also a `DiscriminantKind` type in libcore, it remains unaffected. I think this corresponds to the discriminant, not the tag, so that seems all right.)

r? @EddyB
use self::EnumDiscriminantInfo::*; use self::EnumTagInfo::*;
use self::MemberDescriptionFactory::*; use self::MemberDescriptionFactory::*;
use self::RecursiveTypeDescription::*; use self::RecursiveTypeDescription::*;
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
use rustc_session::config::{self, DebugInfo}; use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::{Interner, Symbol}; use rustc_span::symbol::{Interner, Symbol};
use rustc_span::{self, SourceFile, SourceFileHash, Span}; 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::{Int, Pointer, F32, F64};
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
...@@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names( ...@@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names(
struct EnumMemberDescriptionFactory<'ll, 'tcx> { struct EnumMemberDescriptionFactory<'ll, 'tcx> {
enum_type: Ty<'tcx>, enum_type: Ty<'tcx>,
layout: TyAndLayout<'tcx>, layout: TyAndLayout<'tcx>,
discriminant_type_metadata: Option<&'ll DIType>, tag_type_metadata: Option<&'ll DIType>,
containing_scope: &'ll DIScope, containing_scope: &'ll DIScope,
span: Span, span: Span,
} }
...@@ -1385,7 +1385,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1385,7 +1385,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
cx, cx,
self.layout, self.layout,
variant_info, variant_info,
NoDiscriminant, NoTag,
self_metadata, self_metadata,
self.span, self.span,
); );
...@@ -1409,19 +1409,19 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1409,19 +1409,19 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
}] }]
} }
Variants::Multiple { Variants::Multiple {
discr_kind: DiscriminantKind::Tag, tag_encoding: TagEncoding::Direct,
discr_index, tag_field,
ref variants, ref variants,
.. ..
} => { } => {
let discriminant_info = if fallback { let tag_info = if fallback {
RegularDiscriminant { RegularTag {
discr_field: Field::from(discr_index), tag_field: Field::from(tag_field),
discr_type_metadata: self.discriminant_type_metadata.unwrap(), tag_type_metadata: self.tag_type_metadata.unwrap(),
} }
} else { } else {
// This doesn't matter in this case. // This doesn't matter in this case.
NoDiscriminant NoTag
}; };
variants variants
.iter_enumerated() .iter_enumerated()
...@@ -1432,7 +1432,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1432,7 +1432,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
cx, cx,
variant, variant,
variant_info, variant_info,
discriminant_info, tag_info,
self_metadata, self_metadata,
self.span, self.span,
); );
...@@ -1467,11 +1467,11 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1467,11 +1467,11 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
.collect() .collect()
} }
Variants::Multiple { Variants::Multiple {
discr_kind: tag_encoding:
DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant }, TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
ref discr, ref tag,
ref variants, ref variants,
discr_index, tag_field,
} => { } => {
if fallback { if fallback {
let variant = self.layout.for_variant(cx, dataful_variant); let variant = self.layout.for_variant(cx, dataful_variant);
...@@ -1480,7 +1480,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1480,7 +1480,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
cx, cx,
variant, variant,
variant_info_for(dataful_variant), variant_info_for(dataful_variant),
OptimizedDiscriminant, OptimizedTag,
self.containing_scope, self.containing_scope,
self.span, self.span,
); );
...@@ -1524,8 +1524,8 @@ fn compute_field_path<'a, 'tcx>( ...@@ -1524,8 +1524,8 @@ fn compute_field_path<'a, 'tcx>(
cx, cx,
&mut name, &mut name,
self.layout, self.layout,
self.layout.fields.offset(discr_index), self.layout.fields.offset(tag_field),
self.layout.field(cx, discr_index).size, self.layout.field(cx, tag_field).size,
); );
variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| { variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
name.push_str(variant_name); name.push_str(variant_name);
...@@ -1552,7 +1552,7 @@ fn compute_field_path<'a, 'tcx>( ...@@ -1552,7 +1552,7 @@ fn compute_field_path<'a, 'tcx>(
cx, cx,
variant, variant,
variant_info, variant_info,
OptimizedDiscriminant, OptimizedTag,
self_metadata, self_metadata,
self.span, self.span,
); );
...@@ -1573,7 +1573,7 @@ fn compute_field_path<'a, 'tcx>( ...@@ -1573,7 +1573,7 @@ fn compute_field_path<'a, 'tcx>(
let value = (i.as_u32() as u128) let value = (i.as_u32() as u128)
.wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128)
.wrapping_add(niche_start); .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 // NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise // we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected. // truncation will be silent and remain undetected.
...@@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> { ...@@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> {
/// Cloned from the `layout::Struct` describing the variant. /// Cloned from the `layout::Struct` describing the variant.
offsets: Vec<Size>, offsets: Vec<Size>,
args: Vec<(String, Ty<'tcx>)>, args: Vec<(String, Ty<'tcx>)>,
discriminant_type_metadata: Option<&'ll DIType>, tag_type_metadata: Option<&'ll DIType>,
span: Span, span: Span,
} }
...@@ -1617,7 +1617,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1617,7 +1617,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
MemberDescription { MemberDescription {
name: name.to_string(), name: name.to_string(),
type_metadata: if use_enum_fallback(cx) { 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 // Discriminant is always the first field of our variant
// when using the enum fallback. // when using the enum fallback.
Some(metadata) if i == 0 => metadata, Some(metadata) if i == 0 => metadata,
...@@ -1637,11 +1637,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes ...@@ -1637,11 +1637,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
} }
} }
// FIXME: terminology here should be aligned with `abi::TagEncoding`.
// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum EnumDiscriminantInfo<'ll> { enum EnumTagInfo<'ll> {
RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType }, RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
OptimizedDiscriminant, OptimizedTag,
NoDiscriminant, NoTag,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
...@@ -1706,7 +1709,7 @@ fn describe_enum_variant( ...@@ -1706,7 +1709,7 @@ fn describe_enum_variant(
cx: &CodegenCx<'ll, 'tcx>, cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>, layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>, variant: VariantInfo<'_, 'tcx>,
discriminant_info: EnumDiscriminantInfo<'ll>, discriminant_info: EnumTagInfo<'ll>,
containing_scope: &'ll DIScope, containing_scope: &'ll DIScope,
span: Span, span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
...@@ -1722,12 +1725,12 @@ fn describe_enum_variant( ...@@ -1722,12 +1725,12 @@ fn describe_enum_variant(
let (offsets, args) = if use_enum_fallback(cx) { let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field. // If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info { 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 // 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 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 = 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)) (Some(offset), Some(args))
} }
_ => (None, None), _ => (None, None),
...@@ -1757,8 +1760,8 @@ fn describe_enum_variant( ...@@ -1757,8 +1760,8 @@ fn describe_enum_variant(
let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
offsets, offsets,
args, args,
discriminant_type_metadata: match discriminant_info { tag_type_metadata: match discriminant_info {
RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata), RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
_ => None, _ => None,
}, },
span, span,
...@@ -1880,18 +1883,18 @@ fn prepare_enum_metadata( ...@@ -1880,18 +1883,18 @@ fn prepare_enum_metadata(
if let ( if let (
&Abi::Scalar(_), &Abi::Scalar(_),
&Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. }, &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
) = (&layout.abi, &layout.variants) ) = (&layout.abi, &layout.variants)
{ {
return FinalMetadata(discriminant_type_metadata(discr.value)); return FinalMetadata(discriminant_type_metadata(tag.value));
} }
if use_enum_fallback(cx) { if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants { let discriminant_type_metadata = match layout.variants {
Variants::Single { .. } Variants::Single { .. }
| Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None, | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => { Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
Some(discriminant_type_metadata(discr.value)) Some(discriminant_type_metadata(tag.value))
} }
}; };
...@@ -1927,7 +1930,7 @@ fn prepare_enum_metadata( ...@@ -1927,7 +1930,7 @@ fn prepare_enum_metadata(
EnumMDF(EnumMemberDescriptionFactory { EnumMDF(EnumMemberDescriptionFactory {
enum_type, enum_type,
layout, layout,
discriminant_type_metadata, tag_type_metadata: discriminant_type_metadata,
containing_scope, containing_scope,
span, span,
}), }),
...@@ -1943,16 +1946,13 @@ fn prepare_enum_metadata( ...@@ -1943,16 +1946,13 @@ fn prepare_enum_metadata(
Variants::Single { .. } => None, Variants::Single { .. } => None,
Variants::Multiple { Variants::Multiple {
discr_kind: DiscriminantKind::Niche { .. }, tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
ref discr,
discr_index,
..
} => { } => {
// Find the integer type of the correct size. // Find the integer type of the correct size.
let size = discr.value.size(cx); let size = tag.value.size(cx);
let align = discr.value.align(cx); let align = tag.value.align(cx);
let discr_type = match discr.value { let tag_type = match tag.value {
Int(t, _) => t, Int(t, _) => t,
F32 => Integer::I32, F32 => Integer::I32,
F64 => Integer::I64, F64 => Integer::I64,
...@@ -1960,7 +1960,7 @@ fn prepare_enum_metadata( ...@@ -1960,7 +1960,7 @@ fn prepare_enum_metadata(
} }
.to_ty(cx.tcx, false); .to_ty(cx.tcx, false);
let discr_metadata = basic_type_metadata(cx, discr_type); let tag_metadata = basic_type_metadata(cx, tag_type);
unsafe { unsafe {
Some(llvm::LLVMRustDIBuilderCreateMemberType( Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx), DIB(cx),
...@@ -1971,17 +1971,15 @@ fn prepare_enum_metadata( ...@@ -1971,17 +1971,15 @@ fn prepare_enum_metadata(
UNKNOWN_LINE_NUMBER, UNKNOWN_LINE_NUMBER,
size.bits(), size.bits(),
align.abi.bits() as u32, align.abi.bits() as u32,
layout.fields.offset(discr_index).bits(), layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial, DIFlags::FlagArtificial,
discr_metadata, tag_metadata,
)) ))
} }
} }
Variants::Multiple { Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
discr_kind: DiscriminantKind::Tag, ref discr, discr_index, .. let discr_type = tag.value.to_ty(cx.tcx);
} => {
let discr_type = discr.value.to_ty(cx.tcx);
let (size, align) = cx.size_and_align_of(discr_type); let (size, align) = cx.size_and_align_of(discr_type);
let discr_metadata = basic_type_metadata(cx, discr_type); let discr_metadata = basic_type_metadata(cx, discr_type);
...@@ -1995,7 +1993,7 @@ fn prepare_enum_metadata( ...@@ -1995,7 +1993,7 @@ fn prepare_enum_metadata(
UNKNOWN_LINE_NUMBER, UNKNOWN_LINE_NUMBER,
size.bits(), size.bits(),
align.bits() as u32, align.bits() as u32,
layout.fields.offset(discr_index).bits(), layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial, DIFlags::FlagArtificial,
discr_metadata, discr_metadata,
)) ))
...@@ -2081,7 +2079,7 @@ fn prepare_enum_metadata( ...@@ -2081,7 +2079,7 @@ fn prepare_enum_metadata(
EnumMDF(EnumMemberDescriptionFactory { EnumMDF(EnumMemberDescriptionFactory {
enum_type, enum_type,
layout, layout,
discriminant_type_metadata: None, tag_type_metadata: None,
containing_scope, containing_scope,
span, span,
}), }),
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Ty}; 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}; use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
...@@ -199,7 +199,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( ...@@ -199,7 +199,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
if self.layout.abi.is_uninhabited() { if self.layout.abi.is_uninhabited() {
return bx.cx().const_undef(cast_to); 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 } => { Variants::Single { index } => {
let discr_val = self let discr_val = self
.layout .layout
...@@ -208,33 +208,33 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( ...@@ -208,33 +208,33 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
.map_or(index.as_u32() as u128, |discr| discr.val); .map_or(index.as_u32() as u128, |discr| discr.val);
return bx.cx().const_uint_big(cast_to, discr_val); return bx.cx().const_uint_big(cast_to, discr_val);
} }
Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
(discr, discr_kind, discr_index) (tag, tag_encoding, tag_field)
} }
}; };
// Read the tag/niche-encoded discriminant from memory. // Read the tag/niche-encoded discriminant from memory.
let encoded_discr = self.project_field(bx, discr_index); let tag = self.project_field(bx, tag_field);
let encoded_discr = bx.load_operand(encoded_discr); let tag = bx.load_operand(tag);
// Decode the discriminant (specifically if it's niche-encoded). // Decode the discriminant (specifically if it's niche-encoded).
match *discr_kind { match *tag_encoding {
DiscriminantKind::Tag => { TagEncoding::Direct => {
let signed = match discr_scalar.value { let signed = match tag_scalar.value {
// We use `i1` for bytes that are always `0` or `1`, // We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't // e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because // let LLVM interpret the `i1` as signed, because
// then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. // 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, _ => 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 // Rebase from niche values to discriminants, and check
// whether the result is in range for the niche variants. // whether the result is in range for the niche variants.
let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout); let niche_llty = bx.cx().immediate_backend_type(tag.layout);
let encoded_discr = encoded_discr.immediate(); let tag = tag.immediate();
// We first compute the "relative discriminant" (wrt `niche_variants`), // We first compute the "relative discriminant" (wrt `niche_variants`),
// that is, if `n = niche_variants.end() - niche_variants.start()`, // that is, if `n = niche_variants.end() - niche_variants.start()`,
...@@ -248,9 +248,9 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( ...@@ -248,9 +248,9 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
let relative_discr = if niche_start == 0 { let relative_discr = if niche_start == 0 {
// Avoid subtracting `0`, which wouldn't work for pointers. // Avoid subtracting `0`, which wouldn't work for pointers.
// FIXME(eddyb) check the actual primitive type here. // FIXME(eddyb) check the actual primitive type here.
encoded_discr tag
} else { } 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 relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
let is_niche = { let is_niche = {
...@@ -312,8 +312,8 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( ...@@ -312,8 +312,8 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
Variants::Single { index } => { Variants::Single { index } => {
assert_eq!(index, variant_index); assert_eq!(index, variant_index);
} }
Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => { Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
let ptr = self.project_field(bx, discr_index); let ptr = self.project_field(bx, tag_field);
let to = let to =
self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
bx.store( bx.store(
...@@ -323,9 +323,9 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( ...@@ -323,9 +323,9 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
); );
} }
Variants::Multiple { Variants::Multiple {
discr_kind: tag_encoding:
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start }, TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
discr_index, tag_field,
.. ..
} => { } => {
if variant_index != dataful_variant { if variant_index != dataful_variant {
...@@ -339,7 +339,7 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( ...@@ -339,7 +339,7 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty()); 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_llty = bx.cx().immediate_backend_type(niche.layout);
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
let niche_value = (niche_value as u128).wrapping_add(niche_start); let niche_value = (niche_value as u128).wrapping_add(niche_start);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
use rustc_span::source_map; use rustc_span::source_map;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; 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 rustc_target::spec::abi::Abi;
use log::debug; use log::debug;
...@@ -1056,15 +1056,15 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) { ...@@ -1056,15 +1056,15 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
}; };
let (variants, tag) = match layout.variants { let (variants, tag) = match layout.variants {
Variants::Multiple { Variants::Multiple {
discr_kind: DiscriminantKind::Tag, tag_encoding: TagEncoding::Direct,
ref discr, ref tag,
ref variants, ref variants,
.. ..
} => (variants, discr), } => (variants, tag),
_ => return, _ => return,
}; };
let discr_size = tag.value.size(&cx.tcx).bytes(); let tag_size = tag.value.size(&cx.tcx).bytes();
debug!( debug!(
"enum `{}` is {} bytes large with layout:\n{:#?}", "enum `{}` is {} bytes large with layout:\n{:#?}",
...@@ -1078,8 +1078,8 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) { ...@@ -1078,8 +1078,8 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
.iter() .iter()
.zip(variants) .zip(variants)
.map(|(variant, variant_layout)| { .map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant. // Subtract the size of the enum tag.
let bytes = variant_layout.size.bytes().saturating_sub(discr_size); let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
debug!("- variant `{}` is {} bytes large", variant.ident, bytes); debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
bytes bytes
......
...@@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { ...@@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
InvalidBool(u8), InvalidBool(u8),
/// Using a non-character `u32` as character. /// Using a non-character `u32` as character.
InvalidChar(u32), InvalidChar(u32),
/// An enum discriminant was set to a value which was outside the range of valid values. /// The tag of an enum does not encode an actual discriminant.
InvalidDiscriminant(Scalar), InvalidTag(Scalar),
/// Using a pointer-not-to-a-function as function pointer. /// Using a pointer-not-to-a-function as function pointer.
InvalidFunctionPointer(Pointer), InvalidFunctionPointer(Pointer),
/// Using a string that is not valid UTF-8, /// Using a string that is not valid UTF-8,
...@@ -463,7 +463,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ...@@ -463,7 +463,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
InvalidChar(c) => { InvalidChar(c) => {
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c) write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
} }
InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val), InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
InvalidFunctionPointer(p) => { InvalidFunctionPointer(p) => {
write!(f, "using {} as function pointer but it does not point to a function", p) write!(f, "using {} as function pointer but it does not point to a function", p)
} }
......
...@@ -974,13 +974,13 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError< ...@@ -974,13 +974,13 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
return Ok(tcx.intern_layout(Layout { return Ok(tcx.intern_layout(Layout {
variants: Variants::Multiple { variants: Variants::Multiple {
discr: niche_scalar, tag: niche_scalar,
discr_kind: DiscriminantKind::Niche { tag_encoding: TagEncoding::Niche {
dataful_variant: i, dataful_variant: i,
niche_variants, niche_variants,
niche_start, niche_start,
}, },
discr_index: 0, tag_field: 0,
variants: st, variants: st,
}, },
fields: FieldsShape::Arbitrary { fields: FieldsShape::Arbitrary {
...@@ -1216,9 +1216,9 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError< ...@@ -1216,9 +1216,9 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
tcx.intern_layout(Layout { tcx.intern_layout(Layout {
variants: Variants::Multiple { variants: Variants::Multiple {
discr: tag, tag,
discr_kind: DiscriminantKind::Tag, tag_encoding: TagEncoding::Direct,
discr_index: 0, tag_field: 0,
variants: layout_variants, variants: layout_variants,
}, },
fields: FieldsShape::Arbitrary { fields: FieldsShape::Arbitrary {
...@@ -1399,15 +1399,15 @@ fn generator_layout( ...@@ -1399,15 +1399,15 @@ fn generator_layout(
// Build a prefix layout, including "promoting" all ineligible // Build a prefix layout, including "promoting" all ineligible
// locals as part of the prefix. We compute the layout of all of // locals as part of the prefix. We compute the layout of all of
// these fields at once to get optimal packing. // 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. // `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 max_discr = (info.variant_fields.len() - 1) as u128;
let discr_int = Integer::fit_unsigned(max_discr); let discr_int = Integer::fit_unsigned(max_discr);
let discr_int_ty = discr_int.to_ty(tcx, false); 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 tag = 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 tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout }; let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
let promoted_layouts = ineligible_locals let promoted_layouts = ineligible_locals
.iter() .iter()
...@@ -1418,7 +1418,7 @@ fn generator_layout( ...@@ -1418,7 +1418,7 @@ fn generator_layout(
.as_generator() .as_generator()
.prefix_tys() .prefix_tys()
.map(|ty| self.layout_of(ty)) .map(|ty| self.layout_of(ty))
.chain(iter::once(Ok(discr_layout))) .chain(iter::once(Ok(tag_layout)))
.chain(promoted_layouts) .chain(promoted_layouts)
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let prefix = self.univariant_uninterned( let prefix = self.univariant_uninterned(
...@@ -1441,7 +1441,7 @@ fn generator_layout( ...@@ -1441,7 +1441,7 @@ fn generator_layout(
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
// "outer" and "promoted" fields respectively. // "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_b = offsets.split_off(b_start as usize);
let offsets_a = offsets; let offsets_a = offsets;
...@@ -1558,9 +1558,9 @@ fn generator_layout( ...@@ -1558,9 +1558,9 @@ fn generator_layout(
let layout = tcx.intern_layout(Layout { let layout = tcx.intern_layout(Layout {
variants: Variants::Multiple { variants: Variants::Multiple {
discr, tag: tag,
discr_kind: DiscriminantKind::Tag, tag_encoding: TagEncoding::Direct,
discr_index, tag_field: tag_index,
variants, variants,
}, },
fields: outer_fields, fields: outer_fields,
...@@ -1680,7 +1680,7 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) { ...@@ -1680,7 +1680,7 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
} }
} }
Variants::Multiple { ref discr, ref discr_kind, .. } => { Variants::Multiple { ref tag, ref tag_encoding, .. } => {
debug!( debug!(
"print-type-size `{:#?}` adt general variants def {}", "print-type-size `{:#?}` adt general variants def {}",
layout.ty, layout.ty,
...@@ -1702,8 +1702,8 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) { ...@@ -1702,8 +1702,8 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
record( record(
adt_kind.into(), adt_kind.into(),
adt_packed, adt_packed,
match discr_kind { match tag_encoding {
DiscriminantKind::Tag => Some(discr.value.size(self)), TagEncoding::Direct => Some(tag.value.size(self)),
_ => None, _ => None,
}, },
variant_infos, variant_infos,
...@@ -2028,11 +2028,11 @@ fn for_variant( ...@@ -2028,11 +2028,11 @@ fn for_variant(
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
let tcx = cx.tcx(); let tcx = cx.tcx();
let discr_layout = |discr: &Scalar| -> C::TyAndLayout { let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
let layout = Layout::scalar(cx, discr.clone()); let layout = Layout::scalar(cx, tag.clone());
MaybeResult::from(Ok(TyAndLayout { MaybeResult::from(Ok(TyAndLayout {
layout: tcx.intern_layout(layout), layout: tcx.intern_layout(layout),
ty: discr.value.to_ty(tcx), ty: tag.value.to_ty(tcx),
})) }))
}; };
...@@ -2109,9 +2109,9 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { ...@@ -2109,9 +2109,9 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
.unwrap() .unwrap()
.nth(i) .nth(i)
.unwrap(), .unwrap(),
Variants::Multiple { ref discr, discr_index, .. } => { Variants::Multiple { ref tag, tag_field, .. } => {
if i == discr_index { if i == tag_field {
return discr_layout(discr); return tag_layout(tag);
} }
substs.as_generator().prefix_tys().nth(i).unwrap() substs.as_generator().prefix_tys().nth(i).unwrap()
} }
...@@ -2128,9 +2128,9 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { ...@@ -2128,9 +2128,9 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs), Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
// Discriminant field for enums (where applicable). // Discriminant field for enums (where applicable).
Variants::Multiple { ref discr, .. } => { Variants::Multiple { ref tag, .. } => {
assert_eq!(i, 0); assert_eq!(i, 0);
return discr_layout(discr); return tag_layout(tag);
} }
} }
} }
...@@ -2207,10 +2207,10 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin ...@@ -2207,10 +2207,10 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
// using more niches than just null (e.g., the first page of // using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers). // the address space, or unaligned pointers).
Variants::Multiple { Variants::Multiple {
discr_kind: DiscriminantKind::Niche { dataful_variant, .. }, tag_encoding: TagEncoding::Niche { dataful_variant, .. },
discr_index, 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.for_variant(cx, dataful_variant))
} }
_ => Some(this), _ => Some(this),
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_middle::{mir, ty}; use rustc_middle::{mir, ty};
use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size}; use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants}; use rustc_target::abi::{VariantIdx, Variants};
use super::{ use super::{
...@@ -587,7 +587,6 @@ pub fn read_discriminant( ...@@ -587,7 +587,6 @@ pub fn read_discriminant(
op: OpTy<'tcx, M::PointerTag>, op: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> { ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
trace!("read_discriminant_value {:#?}", op.layout); trace!("read_discriminant_value {:#?}", op.layout);
// Get type and layout of the discriminant. // Get type and layout of the discriminant.
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
trace!("discriminant type: {:?}", discr_layout.ty); trace!("discriminant type: {:?}", discr_layout.ty);
...@@ -596,10 +595,8 @@ pub fn read_discriminant( ...@@ -596,10 +595,8 @@ pub fn read_discriminant(
// This is not to be confused with its "variant index", which is just determining its position in the // 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. // 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 // 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`). // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
// Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
// rather confusing.
let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
Variants::Single { index } => { Variants::Single { index } => {
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) { let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
Some(discr) => { Some(discr) => {
...@@ -615,8 +612,8 @@ pub fn read_discriminant( ...@@ -615,8 +612,8 @@ pub fn read_discriminant(
}; };
return Ok((discr, index)); return Ok((discr, index));
} }
Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
(discr, discr_kind, discr_index) (tag, tag_encoding, tag_field)
} }
}; };
...@@ -633,21 +630,21 @@ pub fn read_discriminant( ...@@ -633,21 +630,21 @@ pub fn read_discriminant(
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
// Read tag and sanity-check `tag_layout`. // 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.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
let tag_val = tag_val.to_scalar()?; let tag_val = tag_val.to_scalar()?;
trace!("tag value: {:?}", tag_val); trace!("tag value: {:?}", tag_val);
// Figure out which discriminant and variant this corresponds to. // Figure out which discriminant and variant this corresponds to.
Ok(match *tag_kind { Ok(match *tag_encoding {
DiscriminantKind::Tag => { TagEncoding::Direct => {
let tag_bits = self let tag_bits = self
.force_bits(tag_val, tag_layout.size) .force_bits(tag_val, tag_layout.size)
.map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; .map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?;
// Cast bits from tag layout to discriminant layout. // 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_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
let discr_bits = discr_val_cast.assert_bits(discr_layout.size); let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants. // Convert discriminant to variant index, and catch invalid discriminants.
let index = match op.layout.ty.kind { let index = match op.layout.ty.kind {
ty::Adt(adt, _) => { ty::Adt(adt, _) => {
...@@ -661,11 +658,11 @@ pub fn read_discriminant( ...@@ -661,11 +658,11 @@ pub fn read_discriminant(
} }
_ => bug!("tagged layout for non-adt non-generator"), _ => bug!("tagged layout for non-adt non-generator"),
} }
.ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; .ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?;
// Return the cast value, and the index. // 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, // Compute the variant this niche value/"tag" corresponds to. With niche layout,
// discriminant (encoded in niche/tag) and variant index are the same. // discriminant (encoded in niche/tag) and variant index are the same.
let variants_start = niche_variants.start().as_u32(); let variants_start = niche_variants.start().as_u32();
...@@ -677,7 +674,7 @@ pub fn read_discriminant( ...@@ -677,7 +674,7 @@ pub fn read_discriminant(
&& variants_start == variants_end && variants_start == variants_end
&& !self.memory.ptr_may_be_null(ptr); && !self.memory.ptr_may_be_null(ptr);
if !ptr_valid { if !ptr_valid {
throw_ub!(InvalidDiscriminant(tag_val.erase_tag())) throw_ub!(InvalidTag(tag_val.erase_tag()))
} }
dataful_variant dataful_variant
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, Ty}; 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 rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{ use super::{
...@@ -1045,7 +1045,8 @@ pub fn allocate_str( ...@@ -1045,7 +1045,8 @@ pub fn allocate_str(
MPlaceTy { mplace, layout } MPlaceTy { mplace, layout }
} }
pub fn write_discriminant_index( /// Writes the discriminant of the given variant.
pub fn write_discriminant(
&mut self, &mut self,
variant_index: VariantIdx, variant_index: VariantIdx,
dest: PlaceTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>,
...@@ -1061,9 +1062,9 @@ pub fn write_discriminant_index( ...@@ -1061,9 +1062,9 @@ pub fn write_discriminant_index(
assert_eq!(index, variant_index); assert_eq!(index, variant_index);
} }
Variants::Multiple { Variants::Multiple {
discr_kind: DiscriminantKind::Tag, tag_encoding: TagEncoding::Direct,
discr: ref discr_layout, tag: ref tag_layout,
discr_index, tag_field,
.. ..
} => { } => {
// No need to validate that the discriminant here because the // No need to validate that the discriminant here because the
...@@ -1075,17 +1076,17 @@ pub fn write_discriminant_index( ...@@ -1075,17 +1076,17 @@ pub fn write_discriminant_index(
// raw discriminants for enums are isize or bigger during // raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible // their computation, but the in-memory tag is the smallest possible
// representation // representation
let size = discr_layout.value.size(self); let size = tag_layout.value.size(self);
let discr_val = truncate(discr_val, size); let tag_val = truncate(discr_val, size);
let discr_dest = self.place_field(dest, discr_index)?; let tag_dest = self.place_field(dest, tag_field)?;
self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?; self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
} }
Variants::Multiple { Variants::Multiple {
discr_kind: tag_encoding:
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start }, TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
discr: ref discr_layout, tag: ref tag_layout,
discr_index, tag_field,
.. ..
} => { } => {
// No need to validate that the discriminant here because the // No need to validate that the discriminant here because the
...@@ -1098,19 +1099,19 @@ pub fn write_discriminant_index( ...@@ -1098,19 +1099,19 @@ pub fn write_discriminant_index(
.checked_sub(variants_start) .checked_sub(variants_start)
.expect("overflow computing relative variant idx"); .expect("overflow computing relative variant idx");
// We need to use machine arithmetic when taking into account `niche_start`: // We need to use machine arithmetic when taking into account `niche_start`:
// discr_val = variant_index_relative + niche_start_val // tag_val = variant_index_relative + niche_start_val
let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
let variant_index_relative_val = let variant_index_relative_val =
ImmTy::from_uint(variant_index_relative, discr_layout); ImmTy::from_uint(variant_index_relative, tag_layout);
let discr_val = self.binary_op( let tag_val = self.binary_op(
mir::BinOp::Add, mir::BinOp::Add,
variant_index_relative_val, variant_index_relative_val,
niche_start_val, niche_start_val,
)?; )?;
// Write result. // Write result.
let niche_dest = self.place_field(dest, discr_index)?; let niche_dest = self.place_field(dest, tag_field)?;
self.write_immediate(*discr_val, niche_dest)?; self.write_immediate(*tag_val, niche_dest)?;
} }
} }
} }
......
...@@ -88,7 +88,7 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { ...@@ -88,7 +88,7 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
SetDiscriminant { place, variant_index } => { SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?; let dest = self.eval_place(**place)?;
self.write_discriminant_index(*variant_index, dest)?; self.write_discriminant(*variant_index, dest)?;
} }
// Mark locals as alive // Mark locals as alive
...@@ -179,7 +179,7 @@ pub fn eval_rvalue_into_place( ...@@ -179,7 +179,7 @@ pub fn eval_rvalue_into_place(
Aggregate(ref kind, ref operands) => { Aggregate(ref kind, ref operands) => {
let (dest, active_field_index) = match **kind { let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { 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() { if adt_def.is_enum() {
(self.place_downcast(dest, variant_index)?, active_field_index) (self.place_downcast(dest, variant_index)?, active_field_index)
} else { } else {
......
...@@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ...@@ -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 { fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
// First, check if we are projecting to a variant. // First, check if we are projecting to a variant.
match layout.variants { match layout.variants {
Variants::Multiple { discr_index, .. } => { Variants::Multiple { tag_field, .. } => {
if discr_index == field { if tag_field == field {
return match layout.ty.kind { return match layout.ty.kind {
ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
ty::Generator(..) => PathElem::GeneratorTag, ty::Generator(..) => PathElem::GeneratorTag,
...@@ -697,8 +697,8 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { ...@@ -697,8 +697,8 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
try_validation!( try_validation!(
self.walk_value(op), self.walk_value(op),
self.path, self.path,
err_ub!(InvalidDiscriminant(val)) => err_ub!(InvalidTag(val)) =>
{ "{}", val } expected { "a valid enum discriminant" }, { "{}", val } expected { "a valid enum tag" },
err_unsup!(ReadPointerAsBytes) => err_unsup!(ReadPointerAsBytes) =>
{ "a pointer" } expected { "plain (non-pointer) bytes" }, { "a pointer" } expected { "plain (non-pointer) bytes" },
); );
......
...@@ -809,25 +809,30 @@ pub enum Variants { ...@@ -809,25 +809,30 @@ pub enum Variants {
/// Single enum variants, structs/tuples, unions, and all non-ADTs. /// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx }, Single { index: VariantIdx },
/// Enum-likes with more than one inhabited variant: for each case there is /// Enum-likes with more than one inhabited variant: each variant comes with
/// a struct, and they all have space reserved for the discriminant. /// a *discriminant* (usually the same as the variant index but the user can
/// For enums this is the sole field of the layout. /// 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 { Multiple {
discr: Scalar, tag: Scalar,
discr_kind: DiscriminantKind, tag_encoding: TagEncoding,
discr_index: usize, tag_field: usize,
variants: IndexVec<VariantIdx, Layout>, variants: IndexVec<VariantIdx, Layout>,
}, },
} }
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum DiscriminantKind { pub enum TagEncoding {
/// Integer tag holding the discriminant value itself. /// The tag directly stores the discriminant, but possibly with a smaller layout
Tag, /// (so converting the tag to the discriminant can require sign extension).
Direct,
/// Niche (values invalid for a type) encoding the discriminant: /// Niche (values invalid for a type) encoding the discriminant:
/// the variant `dataful_variant` contains a niche at an arbitrary /// Discriminant and variant index coincide.
/// offset (field `discr_index` of the enum), which for a variant with /// 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 /// discriminant `d` is set to
/// `(d - niche_variants.start).wrapping_add(niche_start)`. /// `(d - niche_variants.start).wrapping_add(niche_start)`.
/// ///
......
...@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( ...@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {(
LL | | Union { u8: &BAR }.foo, LL | | Union { u8: &BAR }.foo,
LL | | Union { u8: &BAR }.bar, LL | | Union { u8: &BAR }.bar,
LL | | )}; LL | | )};
| |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum discriminant | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum tag
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
......
...@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value ...@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:24:1 --> $DIR/ub-enum.rs:24:1
| |
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum discriminant | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
...@@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value ...@@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:42:1 --> $DIR/ub-enum.rs:42:1
| |
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum discriminant | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
......
...@@ -10,15 +10,15 @@ error: layout_of(E) = Layout { ...@@ -10,15 +10,15 @@ error: layout_of(E) = Layout {
], ],
}, },
variants: Multiple { variants: Multiple {
discr: Scalar { tag: Scalar {
value: Int( value: Int(
I32, I32,
false, false,
), ),
valid_range: 0..=0, valid_range: 0..=0,
}, },
discr_kind: Tag, tag_encoding: Direct,
discr_index: 0, tag_field: 0,
variants: [ variants: [
Layout { Layout {
fields: Arbitrary { fields: Arbitrary {
...@@ -202,15 +202,15 @@ error: layout_of(std::result::Result<i32, i32>) = Layout { ...@@ -202,15 +202,15 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
], ],
}, },
variants: Multiple { variants: Multiple {
discr: Scalar { tag: Scalar {
value: Int( value: Int(
I32, I32,
false, false,
), ),
valid_range: 0..=1, valid_range: 0..=1,
}, },
discr_kind: Tag, tag_encoding: Direct,
discr_index: 0, tag_field: 0,
variants: [ variants: [
Layout { Layout {
fields: Arbitrary { fields: Arbitrary {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册