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::MemberDescriptionFactory::*;
use self::RecursiveTypeDescription::*; use self::RecursiveTypeDescription::*;
@ -40,7 +40,7 @@ use rustc_middle::{bug, span_bug};
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(
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 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx, cx,
self.layout, self.layout,
variant_info, variant_info,
NoDiscriminant, NoTag,
self_metadata, self_metadata,
self.span, self.span,
); );
@ -1409,19 +1409,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
}] }]
} }
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 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx, cx,
variant, variant,
variant_info, variant_info,
discriminant_info, tag_info,
self_metadata, self_metadata,
self.span, self.span,
); );
@ -1467,11 +1467,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
.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 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
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 @@ impl EnumMemberDescriptionFactory<'ll, '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 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx, cx,
variant, variant,
variant_info, variant_info,
OptimizedDiscriminant, OptimizedTag,
self_metadata, self_metadata,
self.span, self.span,
); );
@ -1573,7 +1573,7 @@ impl EnumMemberDescriptionFactory<'ll, '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> {
/// 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 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
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,
@ -1638,10 +1638,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
} }
#[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 +1706,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 +1722,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 +1757,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 +1880,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 +1927,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 +1943,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 +1957,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 +1968,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 +1990,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 +2076,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,
}), }),

View file

@ -10,7 +10,7 @@ use rustc_middle::mir;
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 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, 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 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, 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 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, 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 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, 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 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, 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 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, 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);

View file

@ -16,7 +16,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
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;
@ -1036,15 +1036,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
}; };
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{:#?}",
@ -1058,8 +1058,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
.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

View file

@ -975,13 +975,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
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 {
@ -1217,9 +1217,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
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 {
@ -1400,15 +1400,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// 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()
@ -1419,7 +1419,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
.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(
@ -1442,7 +1442,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// "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;
@ -1559,9 +1559,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
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,
@ -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!( debug!(
"print-type-size `{:#?}` adt general variants def {}", "print-type-size `{:#?}` adt general variants def {}",
layout.ty, layout.ty,
@ -1703,8 +1703,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'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,
@ -2029,11 +2029,11 @@ where
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),
})) }))
}; };
@ -2110,9 +2110,9 @@ where
.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()
} }
@ -2129,9 +2129,9 @@ where
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);
} }
} }
} }
@ -2208,10 +2208,10 @@ where
// 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),

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::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, TagEncoding, HasDataLayout, LayoutOf, Size};
use rustc_target::abi::{VariantIdx, Variants}; use rustc_target::abi::{VariantIdx, Variants};
use super::{ use super::{
@ -587,7 +587,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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 @@ 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 // 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 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}; };
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 @@ 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))?; 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!(InvalidDiscriminant(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, _) => {
@ -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())))?; .ok_or_else(|| err_ub!(InvalidDiscriminant(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();

View file

@ -9,7 +9,7 @@ use rustc_macros::HashStable;
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::{
@ -1031,7 +1031,8 @@ where
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>,
@ -1047,9 +1048,9 @@ where
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
@ -1061,17 +1062,17 @@ where
// 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
@ -1084,19 +1085,19 @@ where
.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)?;
} }
} }
} }

View file

@ -89,7 +89,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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
@ -174,7 +174,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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 {

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 { 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,

View file

@ -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)`.
/// ///

View file

@ -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 {
], ],
}, },
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 {