about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs660
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs90
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs52
-rw-r--r--compiler/rustc_index/src/vec.rs4
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp24
-rw-r--r--src/etc/natvis/intrinsic.natvis180
-rw-r--r--src/test/debuginfo/generator-objects.rs5
-rw-r--r--src/test/debuginfo/msvc-pretty-enums.rs142
-rw-r--r--src/test/debuginfo/msvc-scalarpair-params.rs4
-rw-r--r--src/test/debuginfo/pretty-std.rs14
-rw-r--r--src/test/debuginfo/type-names.rs4
15 files changed, 846 insertions, 368 deletions
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index bd84100e0e8..25a989bdf05 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -114,6 +114,7 @@ macro_rules! return_if_di_node_created_in_meantime {
 }
 
 /// Extract size and alignment from a TyAndLayout.
+#[inline]
 fn size_and_align_of<'tcx>(ty_and_layout: TyAndLayout<'tcx>) -> (Size, Align) {
     (ty_and_layout.size, ty_and_layout.align.abi)
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index d6e2c8ccdf4..55bdd29d67c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -1,19 +1,20 @@
 use std::borrow::Cow;
 
 use libc::c_uint;
-use rustc_codegen_ssa::debuginfo::{
-    type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo,
+use rustc_codegen_ssa::{
+    debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
+    traits::ConstMethods,
 };
+use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::{
     bug,
     ty::{
         self,
         layout::{LayoutOf, TyAndLayout},
-        util::Discr,
-        AdtDef, GeneratorSubsts,
+        AdtDef, GeneratorSubsts, Ty,
     },
 };
-use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
+use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
 use smallvec::smallvec;
 
 use crate::{
@@ -21,9 +22,9 @@ use crate::{
     debuginfo::{
         metadata::{
             build_field_di_node, closure_saved_names_of_captured_variables,
-            enums::tag_base_type,
-            file_metadata, generator_layout_and_saved_local_names, size_and_align_of,
-            type_map::{self, UniqueTypeId},
+            enums::{tag_base_type, DiscrResult},
+            file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node,
+            type_map::{self, Stub, UniqueTypeId},
             unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA,
             UNKNOWN_LINE_NUMBER,
         },
@@ -35,59 +36,78 @@ use crate::{
     },
 };
 
-/// In CPP-like mode, we generate a union of structs for each variant and an
-/// explicit discriminant field roughly equivalent to the following C/C++ code:
+// The names of the associated constants in each variant wrapper struct.
+// These have to match up with the names being used in `intrinsic.natvis`.
+const ASSOC_CONST_DISCR_NAME: &str = "NAME";
+const ASSOC_CONST_DISCR_EXACT: &str = "DISCR_EXACT";
+const ASSOC_CONST_DISCR_BEGIN: &str = "DISCR_BEGIN";
+const ASSOC_CONST_DISCR_END: &str = "DISCR_END";
+
+const ASSOC_CONST_DISCR128_EXACT_LO: &str = "DISCR128_EXACT_LO";
+const ASSOC_CONST_DISCR128_EXACT_HI: &str = "DISCR128_EXACT_HI";
+const ASSOC_CONST_DISCR128_BEGIN_LO: &str = "DISCR128_BEGIN_LO";
+const ASSOC_CONST_DISCR128_BEGIN_HI: &str = "DISCR128_BEGIN_HI";
+const ASSOC_CONST_DISCR128_END_LO: &str = "DISCR128_END_LO";
+const ASSOC_CONST_DISCR128_END_HI: &str = "DISCR128_END_HI";
+
+// The name of the tag field in the top-level union
+const TAG_FIELD_NAME: &str = "tag";
+const TAG_FIELD_NAME_128_LO: &str = "tag128_lo";
+const TAG_FIELD_NAME_128_HI: &str = "tag128_hi";
+
+// We assign a "virtual" discriminant value to the sole variant of
+// a single-variant enum.
+const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0;
+
+/// In CPP-like mode, we generate a union with a field for each variant and an
+/// explicit tag field. The field of each variant has a struct type
+/// that encodes the discrimiant of the variant and it's data layout.
+/// The union also has a nested enumeration type that is only used for encoding
+/// variant names in an efficient way. Its enumerator values do _not_ correspond
+/// to the enum's discriminant values.
+/// It's roughly equivalent to the following C/C++ code:
 ///
 /// ```c
 /// union enum$<{fully-qualified-name}> {
-///   struct {variant 0 name} {
-///     <variant 0 fields>
+///   struct Variant0 {
+///     struct {name-of-variant-0} {
+///        <variant 0 fields>
+///     } value;
+///
+///     static VariantNames NAME = {name-of-variant-0};
+///     static int_type DISCR_EXACT = {discriminant-of-variant-0};
 ///   } variant0;
+///
 ///   <other variant structs>
-///   {name} discriminant;
+///
+///   int_type tag;
+///
+///   enum VariantNames {
+///      <name-of-variant-0> = 0, // The numeric values are variant index,
+///      <name-of-variant-1> = 1, // not discriminant values.
+///      <name-of-variant-2> = 2,
+///      ...
+///   }
 /// }
 /// ```
 ///
 /// As you can see, the type name is wrapped `enum$`. This way we can have a
 /// single NatVis rule for handling all enums.
 ///
-/// At the LLVM IR level this looks like
-///
-/// ```txt
-///       DW_TAG_union_type              (top-level type for enum)
-///         DW_TAG_member                    (member for variant 1)
-///         DW_TAG_member                    (member for variant 2)
-///         DW_TAG_member                    (member for variant 3)
-///         DW_TAG_structure_type            (type of variant 1)
-///         DW_TAG_structure_type            (type of variant 2)
-///         DW_TAG_structure_type            (type of variant 3)
-///         DW_TAG_enumeration_type          (type of tag)
-/// ```
+/// For niche-tag enums, a variant might correspond to a range of tag values.
+/// In that case the variant struct has a `DISCR_BEGIN` and `DISCR_END` field
+/// instead of DISCR_EXACT.
 ///
-/// The above encoding applies for enums with a direct tag. For niche-tag we have to do things
-/// differently in order to allow a NatVis visualizer to extract all the information needed:
-/// We generate a union of two fields, one for the dataful variant
-/// and one that just points to the discriminant (which is some field within the dataful variant).
-/// We also create a DW_TAG_enumeration_type DIE that contains tag values for the non-dataful
-/// variants and make the discriminant field that type. We then use NatVis to render the enum type
-/// correctly in Windbg/VS. This will generate debuginfo roughly equivalent to the following C:
+/// Single-variant enums don't actually have a tag field. In this case we
+/// emit a static tag field (that always has the value 0) so we can use the
+/// same representation (and NatVis).
 ///
-/// ```c
-/// union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
-///   struct <dataful variant name> {
-///     <fields in dataful variant>
-///   } dataful_variant;
-///   enum Discriminant$ {
-///     <non-dataful variants>
-///   } discriminant;
-/// }
-/// ```
-///
-/// The NatVis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>`
-/// and evaluates `this.discriminant`. If the value is between the min niche and max
-/// niche, then the enum is in the dataful variant and `this.dataful_variant` is
-/// rendered. Otherwise, the enum is in one of the non-dataful variants. In that
-/// case, we just need to render the name of the `this.discriminant` enum.
+/// For niche-layout enums it's possible to have a 128-bit tag. NatVis, VS, and
+/// WinDbg (the main targets for CPP-like debuginfo at the moment) don't support
+/// 128-bit integers, so all values involved get split into two 64-bit fields.
+/// Instead of the `tag` field, we generate two fields `tag128_lo` and `tag128_hi`,
+/// Instead of `DISCR_EXACT`, we generate `DISCR128_EXACT_LO` and `DISCR128_EXACT_HI`,
+/// and so on.
 pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId<'tcx>,
@@ -135,27 +155,28 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
                     ref variants,
                     tag_field,
                     ..
-                } => build_union_fields_for_direct_tag_enum(
+                } => build_union_fields_for_enum(
                     cx,
                     enum_adt_def,
                     enum_type_and_layout,
                     enum_type_di_node,
-                    &mut variants.indices(),
+                    variants.indices(),
                     tag_field,
+                    None,
                 ),
                 Variants::Multiple {
                     tag_encoding: TagEncoding::Niche { dataful_variant, .. },
                     ref variants,
                     tag_field,
                     ..
-                } => build_union_fields_for_niche_tag_enum(
+                } => build_union_fields_for_enum(
                     cx,
                     enum_adt_def,
                     enum_type_and_layout,
                     enum_type_di_node,
-                    dataful_variant,
-                    &mut variants.indices(),
+                    variants.indices(),
                     tag_field,
+                    Some(dataful_variant),
                 ),
             }
         },
@@ -217,137 +238,344 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
     let variant_layout = enum_type_and_layout.for_variant(cx, variant_index);
     let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node(
         cx,
-        enum_type_and_layout.ty,
+        enum_type_and_layout,
         enum_type_di_node,
         variant_index,
         enum_adt_def.variant(variant_index),
         variant_layout,
     );
 
-    // NOTE: The field name of the union is the same as the variant name, not "variant0".
-    let variant_name = enum_adt_def.variant(variant_index).name.as_str();
+    let tag_base_type = cx.tcx.types.u32;
+    let tag_base_type_di_node = type_di_node(cx, tag_base_type);
+    let tag_base_type_align = cx.align_of(tag_base_type);
 
-    smallvec![build_field_di_node(
+    let variant_names_type_di_node = build_variant_names_type_di_node(
         cx,
         enum_type_di_node,
-        variant_name,
-        // NOTE: We use the size and align of the entire type, not from variant_layout
-        //       since the later is sometimes smaller (if it has fewer fields).
-        size_and_align_of(enum_type_and_layout),
-        Size::ZERO,
-        DIFlags::FlagZero,
+        std::iter::once((
+            variant_index,
+            Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
+        )),
+    );
+
+    let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node(
+        cx,
+        enum_type_and_layout,
+        enum_type_di_node,
+        variant_index,
+        None,
         variant_struct_type_di_node,
-    )]
+        variant_names_type_di_node,
+        tag_base_type_di_node,
+        tag_base_type,
+        DiscrResult::NoDiscriminant,
+    );
+
+    smallvec![
+        build_field_di_node(
+            cx,
+            enum_type_di_node,
+            &variant_union_field_name(variant_index, None),
+            // NOTE: We use the size and align of the entire type, not from variant_layout
+            //       since the later is sometimes smaller (if it has fewer fields).
+            size_and_align_of(enum_type_and_layout),
+            Size::ZERO,
+            DIFlags::FlagZero,
+            variant_struct_type_wrapper_di_node,
+        ),
+        unsafe {
+            llvm::LLVMRustDIBuilderCreateStaticMemberType(
+                DIB(cx),
+                enum_type_di_node,
+                TAG_FIELD_NAME.as_ptr().cast(),
+                TAG_FIELD_NAME.len(),
+                unknown_file_metadata(cx),
+                UNKNOWN_LINE_NUMBER,
+                variant_names_type_di_node,
+                DIFlags::FlagArtificial,
+                Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)),
+                tag_base_type_align.bits() as u32,
+            )
+        }
+    ]
 }
 
-fn build_union_fields_for_direct_tag_enum<'ll, 'tcx>(
+fn build_union_fields_for_enum<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     enum_adt_def: AdtDef<'tcx>,
     enum_type_and_layout: TyAndLayout<'tcx>,
     enum_type_di_node: &'ll DIType,
-    variant_indices: &mut dyn Iterator<Item = VariantIdx>,
+    variant_indices: impl Iterator<Item = VariantIdx> + Clone,
     tag_field: usize,
+    dataful_variant_index: Option<VariantIdx>,
 ) -> SmallVec<&'ll DIType> {
+    let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
+
+    let variant_names_type_di_node = build_variant_names_type_di_node(
+        cx,
+        enum_type_di_node,
+        variant_indices.clone().map(|variant_index| {
+            let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
+            (variant_index, variant_name)
+        }),
+    );
+
     let variant_field_infos: SmallVec<VariantFieldInfo<'ll>> = variant_indices
         .map(|variant_index| {
             let variant_layout = enum_type_and_layout.for_variant(cx, variant_index);
 
+            let variant_def = enum_adt_def.variant(variant_index);
+
+            let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node(
+                cx,
+                enum_type_and_layout,
+                enum_type_di_node,
+                variant_index,
+                variant_def,
+                variant_layout,
+            );
+
             VariantFieldInfo {
                 variant_index,
-                variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node(
-                    cx,
-                    enum_type_and_layout.ty,
-                    enum_type_di_node,
-                    variant_index,
-                    enum_adt_def.variant(variant_index),
-                    variant_layout,
-                ),
+                variant_struct_type_di_node,
                 source_info: None,
+                discr: super::compute_discriminant_value(cx, enum_type_and_layout, variant_index),
             }
         })
         .collect();
 
-    let discr_type_name = cx.tcx.item_name(enum_adt_def.did());
-    let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
-    let discr_type_di_node = super::build_enumeration_type_di_node(
-        cx,
-        discr_type_name.as_str(),
-        tag_base_type,
-        &mut enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
-            (discr, Cow::from(enum_adt_def.variant(variant_index).name.as_str()))
-        }),
-        enum_type_di_node,
-    );
-
     build_union_fields_for_direct_tag_enum_or_generator(
         cx,
         enum_type_and_layout,
         enum_type_di_node,
         &variant_field_infos,
-        discr_type_di_node,
+        variant_names_type_di_node,
+        tag_base_type,
         tag_field,
+        dataful_variant_index,
     )
 }
 
-fn build_union_fields_for_niche_tag_enum<'ll, 'tcx>(
+// The base type of the VariantNames DW_AT_enumeration_type is always the same.
+// It has nothing to do with the tag of the enum and just has to be big enough
+// to hold all variant names.
+fn variant_names_enum_base_type<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> Ty<'tcx> {
+    cx.tcx.types.u32
+}
+
+/// This function builds a DW_AT_enumeration_type that contains an entry for
+/// each variant. Note that this has nothing to do with the discriminant. The
+/// numeric value of each enumerator corresponds to the variant index. The
+/// type is only used for efficiently encoding the name of each variant in
+/// debuginfo.
+fn build_variant_names_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
-    enum_adt_def: AdtDef<'tcx>,
-    enum_type_and_layout: TyAndLayout<'tcx>,
-    enum_type_di_node: &'ll DIType,
-    dataful_variant_index: VariantIdx,
-    variant_indices: &mut dyn Iterator<Item = VariantIdx>,
-    tag_field: usize,
-) -> SmallVec<&'ll DIType> {
-    let dataful_variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node(
+    containing_scope: &'ll DIType,
+    variants: impl Iterator<Item = (VariantIdx, Cow<'tcx, str>)>,
+) -> &'ll DIType {
+    // Create an enumerator for each variant.
+    super::build_enumeration_type_di_node(
         cx,
-        enum_type_and_layout.ty,
-        enum_type_di_node,
-        dataful_variant_index,
-        &enum_adt_def.variant(dataful_variant_index),
-        enum_type_and_layout.for_variant(cx, dataful_variant_index),
-    );
+        "VariantNames",
+        variant_names_enum_base_type(cx),
+        variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32() as u64)),
+        containing_scope,
+    )
+}
 
-    let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
-    // Create an DW_TAG_enumerator for each variant except the dataful one.
-    let discr_type_di_node = super::build_enumeration_type_di_node(
+fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    enum_or_generator_type_and_layout: TyAndLayout<'tcx>,
+    enum_or_generator_type_di_node: &'ll DIType,
+    variant_index: VariantIdx,
+    dataful_variant_index: Option<VariantIdx>,
+    variant_struct_type_di_node: &'ll DIType,
+    variant_names_type_di_node: &'ll DIType,
+    tag_base_type_di_node: &'ll DIType,
+    tag_base_type: Ty<'tcx>,
+    discr: DiscrResult,
+) -> &'ll DIType {
+    type_map::build_type_with_children(
         cx,
-        "Discriminant$",
-        tag_base_type,
-        &mut variant_indices.filter_map(|variant_index| {
-            if let Some(discr_val) =
-                super::compute_discriminant_value(cx, enum_type_and_layout, variant_index)
-            {
-                let discr = Discr { val: discr_val as u128, ty: tag_base_type };
-                let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
-                Some((discr, variant_name))
-            } else {
-                debug_assert_eq!(variant_index, dataful_variant_index);
-                None
-            }
-        }),
-        enum_type_di_node,
-    );
-
-    smallvec![
-        build_field_di_node(
-            cx,
-            enum_type_di_node,
-            "dataful_variant",
-            size_and_align_of(enum_type_and_layout),
-            Size::ZERO,
-            DIFlags::FlagZero,
-            dataful_variant_struct_type_di_node,
-        ),
-        build_field_di_node(
+        type_map::stub(
             cx,
-            enum_type_di_node,
-            "discriminant",
-            cx.size_and_align_of(tag_base_type),
-            enum_type_and_layout.fields.offset(tag_field),
-            DIFlags::FlagZero,
-            discr_type_di_node,
+            Stub::Struct,
+            UniqueTypeId::for_enum_variant_struct_type_wrapper(
+                cx.tcx,
+                enum_or_generator_type_and_layout.ty,
+                variant_index,
+            ),
+            &variant_struct_wrapper_type_name(variant_index),
+            // NOTE: We use size and align of enum_type, not from variant_layout:
+            size_and_align_of(enum_or_generator_type_and_layout),
+            Some(enum_or_generator_type_di_node),
+            DIFlags::FlagArtificial,
         ),
-    ]
+        |cx, wrapper_struct_type_di_node| {
+            enum DiscrKind {
+                Exact(u64),
+                Exact128(u128),
+                Range(u64, u64),
+                Range128(u128, u128),
+            }
+
+            let (tag_base_type_size, tag_base_type_align) = cx.size_and_align_of(tag_base_type);
+            let is_128_bits = tag_base_type_size.bits() > 64;
+
+            let discr = match discr {
+                DiscrResult::NoDiscriminant => DiscrKind::Exact(SINGLE_VARIANT_VIRTUAL_DISR),
+                DiscrResult::Value(discr_val) => {
+                    if is_128_bits {
+                        DiscrKind::Exact128(discr_val)
+                    } else {
+                        debug_assert_eq!(discr_val, discr_val as u64 as u128);
+                        DiscrKind::Exact(discr_val as u64)
+                    }
+                }
+                DiscrResult::Range(min, max) => {
+                    assert_eq!(Some(variant_index), dataful_variant_index);
+                    if is_128_bits {
+                        DiscrKind::Range128(min, max)
+                    } else {
+                        debug_assert_eq!(min, min as u64 as u128);
+                        debug_assert_eq!(max, max as u64 as u128);
+                        DiscrKind::Range(min as u64, max as u64)
+                    }
+                }
+            };
+
+            let mut fields = SmallVec::new();
+
+            // We always have a field for the value
+            fields.push(build_field_di_node(
+                cx,
+                wrapper_struct_type_di_node,
+                "value",
+                size_and_align_of(enum_or_generator_type_and_layout),
+                Size::ZERO,
+                DIFlags::FlagArtificial,
+                variant_struct_type_di_node,
+            ));
+
+            let build_assoc_const =
+                |name: &str, type_di_node: &'ll DIType, value: u64, align: Align| unsafe {
+                    llvm::LLVMRustDIBuilderCreateStaticMemberType(
+                        DIB(cx),
+                        wrapper_struct_type_di_node,
+                        name.as_ptr().cast(),
+                        name.len(),
+                        unknown_file_metadata(cx),
+                        UNKNOWN_LINE_NUMBER,
+                        type_di_node,
+                        DIFlags::FlagArtificial,
+                        Some(cx.const_u64(value)),
+                        align.bits() as u32,
+                    )
+                };
+
+            // We also always have an associated constant for the discriminant value
+            // of the variant.
+            fields.push(build_assoc_const(
+                ASSOC_CONST_DISCR_NAME,
+                variant_names_type_di_node,
+                variant_index.as_u32() as u64,
+                cx.align_of(variant_names_enum_base_type(cx)),
+            ));
+
+            // Emit the discriminant value (or range) corresponding to the variant.
+            match discr {
+                DiscrKind::Exact(discr_val) => {
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR_EXACT,
+                        tag_base_type_di_node,
+                        discr_val,
+                        tag_base_type_align,
+                    ));
+                }
+                DiscrKind::Exact128(discr_val) => {
+                    let align = cx.align_of(cx.tcx.types.u64);
+                    let type_di_node = type_di_node(cx, cx.tcx.types.u64);
+                    let Split128 { hi, lo } = split_128(discr_val);
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR128_EXACT_LO,
+                        type_di_node,
+                        lo,
+                        align,
+                    ));
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR128_EXACT_HI,
+                        type_di_node,
+                        hi,
+                        align,
+                    ));
+                }
+                DiscrKind::Range(begin, end) => {
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR_BEGIN,
+                        tag_base_type_di_node,
+                        begin,
+                        tag_base_type_align,
+                    ));
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR_END,
+                        tag_base_type_di_node,
+                        end,
+                        tag_base_type_align,
+                    ));
+                }
+                DiscrKind::Range128(begin, end) => {
+                    let align = cx.align_of(cx.tcx.types.u64);
+                    let type_di_node = type_di_node(cx, cx.tcx.types.u64);
+                    let Split128 { hi: begin_hi, lo: begin_lo } = split_128(begin);
+                    let Split128 { hi: end_hi, lo: end_lo } = split_128(end);
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR128_BEGIN_HI,
+                        type_di_node,
+                        begin_hi,
+                        align,
+                    ));
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR128_BEGIN_LO,
+                        type_di_node,
+                        begin_lo,
+                        align,
+                    ));
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR128_END_HI,
+                        type_di_node,
+                        end_hi,
+                        align,
+                    ));
+
+                    fields.push(build_assoc_const(
+                        ASSOC_CONST_DISCR128_END_LO,
+                        type_di_node,
+                        end_lo,
+                        align,
+                    ));
+                }
+            }
+
+            fields
+        },
+        NO_GENERICS,
+    )
+    .di_node
+}
+
+struct Split128 {
+    hi: u64,
+    lo: u64,
+}
+
+fn split_128(value: u128) -> Split128 {
+    Split128 { hi: (value >> 64) as u64, lo: value as u64 }
 }
 
 fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
@@ -370,6 +598,21 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
     let common_upvar_names = closure_saved_names_of_captured_variables(cx.tcx, generator_def_id);
     let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx);
 
+    let tag_base_type = tag_base_type(cx, generator_type_and_layout);
+
+    let variant_names_type_di_node = build_variant_names_type_di_node(
+        cx,
+        generator_type_di_node,
+        variant_range
+            .clone()
+            .map(|variant_index| (variant_index, GeneratorSubsts::variant_name(variant_index))),
+    );
+
+    let discriminants: FxHashMap<VariantIdx, DiscrResult> = generator_substs
+        .discriminants(generator_def_id, cx.tcx)
+        .map(|(variant_index, discr)| (variant_index, DiscrResult::Value(discr.val)))
+        .collect();
+
     // Build the type node for each field.
     let variant_field_infos: SmallVec<VariantFieldInfo<'ll>> = variant_range
         .map(|variant_index| {
@@ -391,29 +634,24 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
                 None
             };
 
-            VariantFieldInfo { variant_index, variant_struct_type_di_node, source_info }
+            VariantFieldInfo {
+                variant_index,
+                variant_struct_type_di_node,
+                source_info,
+                discr: discriminants[&variant_index],
+            }
         })
         .collect();
 
-    let tag_base_type = tag_base_type(cx, generator_type_and_layout);
-    let discr_type_name = "Discriminant$";
-    let discr_type_di_node = super::build_enumeration_type_di_node(
-        cx,
-        discr_type_name,
-        tag_base_type,
-        &mut generator_substs
-            .discriminants(generator_def_id, cx.tcx)
-            .map(|(variant_index, discr)| (discr, GeneratorSubsts::variant_name(variant_index))),
-        generator_type_di_node,
-    );
-
     build_union_fields_for_direct_tag_enum_or_generator(
         cx,
         generator_type_and_layout,
         generator_type_di_node,
         &variant_field_infos[..],
-        discr_type_di_node,
+        variant_names_type_di_node,
+        tag_base_type,
         tag_field,
+        None,
     )
 }
 
@@ -425,8 +663,11 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
     enum_type_di_node: &'ll DIType,
     variant_field_infos: &[VariantFieldInfo<'ll>],
     discr_type_di_node: &'ll DIType,
+    tag_base_type: Ty<'tcx>,
     tag_field: usize,
+    dataful_variant_index: Option<VariantIdx>,
 ) -> SmallVec<&'ll DIType> {
+    let tag_base_type_di_node = type_di_node(cx, tag_base_type);
     let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1);
 
     // We create a field in the union for each variant ...
@@ -435,9 +676,23 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
             .source_info
             .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
 
-        let field_name = variant_union_field_name(variant_member_info.variant_index);
+        let field_name =
+            variant_union_field_name(variant_member_info.variant_index, dataful_variant_index);
         let (size, align) = size_and_align_of(enum_type_and_layout);
 
+        let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node(
+            cx,
+            enum_type_and_layout,
+            enum_type_di_node,
+            variant_member_info.variant_index,
+            dataful_variant_index,
+            variant_member_info.variant_struct_type_di_node,
+            discr_type_di_node,
+            tag_base_type_di_node,
+            tag_base_type,
+            variant_member_info.discr,
+        );
+
         // We use LLVMRustDIBuilderCreateMemberType() member type directly because
         // the build_field_di_node() function does not support specifying a source location,
         // which is something that we don't do anywhere else.
@@ -456,7 +711,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
                 // Union fields are always at offset zero
                 Size::ZERO.bits(),
                 DIFlags::FlagZero,
-                variant_member_info.variant_struct_type_di_node,
+                variant_struct_type_wrapper,
             )
         }
     }));
@@ -466,16 +721,53 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
         cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout))
     );
 
-    // ... and a field for the discriminant.
-    unions_fields.push(build_field_di_node(
-        cx,
-        enum_type_di_node,
-        "discriminant",
-        cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
-        enum_type_and_layout.fields.offset(tag_field),
-        DIFlags::FlagZero,
-        discr_type_di_node,
-    ));
+    // ... and a field for the tag. If the tag is 128 bits wide, this will actually
+    // be two 64-bit fields.
+    let is_128_bits = cx.size_of(tag_base_type).bits() > 64;
+
+    if is_128_bits {
+        let type_di_node = type_di_node(cx, cx.tcx.types.u64);
+        let size_and_align = cx.size_and_align_of(cx.tcx.types.u64);
+
+        let (lo_offset, hi_offset) = match cx.tcx.data_layout.endian {
+            Endian::Little => (0, 8),
+            Endian::Big => (8, 0),
+        };
+
+        let tag_field_offset = enum_type_and_layout.fields.offset(tag_field).bytes();
+        let lo_offset = Size::from_bytes(tag_field_offset + lo_offset);
+        let hi_offset = Size::from_bytes(tag_field_offset + hi_offset);
+
+        unions_fields.push(build_field_di_node(
+            cx,
+            enum_type_di_node,
+            TAG_FIELD_NAME_128_LO,
+            size_and_align,
+            lo_offset,
+            DIFlags::FlagZero,
+            type_di_node,
+        ));
+
+        unions_fields.push(build_field_di_node(
+            cx,
+            enum_type_di_node,
+            TAG_FIELD_NAME_128_HI,
+            size_and_align,
+            hi_offset,
+            DIFlags::FlagZero,
+            type_di_node,
+        ));
+    } else {
+        unions_fields.push(build_field_di_node(
+            cx,
+            enum_type_di_node,
+            TAG_FIELD_NAME,
+            cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
+            enum_type_and_layout.fields.offset(tag_field),
+            DIFlags::FlagZero,
+            tag_base_type_di_node,
+        ));
+    }
 
     unions_fields
 }
@@ -485,9 +777,13 @@ struct VariantFieldInfo<'ll> {
     variant_index: VariantIdx,
     variant_struct_type_di_node: &'ll DIType,
     source_info: Option<(&'ll DIFile, c_uint)>,
+    discr: DiscrResult,
 }
 
-fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> {
+fn variant_union_field_name(
+    variant_index: VariantIdx,
+    dataful_variant_index: Option<VariantIdx>,
+) -> Cow<'static, str> {
     const PRE_ALLOCATED: [&str; 16] = [
         "variant0",
         "variant1",
@@ -507,8 +803,38 @@ fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> {
         "variant15",
     ];
 
+    if Some(variant_index) == dataful_variant_index {
+        return Cow::from("variant_fallback");
+    }
+
     PRE_ALLOCATED
         .get(variant_index.as_usize())
         .map(|&s| Cow::from(s))
         .unwrap_or_else(|| format!("variant{}", variant_index.as_usize()).into())
 }
+
+fn variant_struct_wrapper_type_name(variant_index: VariantIdx) -> Cow<'static, str> {
+    const PRE_ALLOCATED: [&str; 16] = [
+        "Variant0",
+        "Variant1",
+        "Variant2",
+        "Variant3",
+        "Variant4",
+        "Variant5",
+        "Variant6",
+        "Variant7",
+        "Variant8",
+        "Variant9",
+        "Variant10",
+        "Variant11",
+        "Variant12",
+        "Variant13",
+        "Variant14",
+        "Variant15",
+    ];
+
+    PRE_ALLOCATED
+        .get(variant_index.as_usize())
+        .map(|&s| Cow::from(s))
+        .unwrap_or_else(|| format!("Variant{}", variant_index.as_usize()).into())
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 73e01d0453b..9b3d080bfd6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -10,7 +10,6 @@ use rustc_middle::{
     ty::{
         self,
         layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
-        util::Discr,
         AdtDef, GeneratorSubsts, Ty, VariantDef,
     },
 };
@@ -90,8 +89,11 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
             cx,
             &compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
             tag_base_type(cx, enum_type_and_layout),
-            &mut enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
-                (discr, Cow::from(enum_adt_def.variant(variant_index).name.as_str()))
+            enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
+                let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
+                // Is there anything we can do to support 128-bit C-Style enums?
+                let value = discr.val as u64;
+                (name, value)
             }),
             containing_scope,
         ),
@@ -152,7 +154,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     type_name: &str,
     base_type: Ty<'tcx>,
-    variants: &mut dyn Iterator<Item = (Discr<'tcx>, Cow<'tcx, str>)>,
+    enumerators: impl Iterator<Item = (Cow<'tcx, str>, u64)>,
     containing_scope: &'ll DIType,
 ) -> &'ll DIType {
     let is_unsigned = match base_type.kind() {
@@ -161,18 +163,15 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
         _ => bug!("build_enumeration_type_di_node() called with non-integer tag type."),
     };
 
-    let enumerator_di_nodes: SmallVec<Option<&'ll DIType>> = variants
-        .map(|(discr, variant_name)| {
-            unsafe {
-                Some(llvm::LLVMRustDIBuilderCreateEnumerator(
-                    DIB(cx),
-                    variant_name.as_ptr().cast(),
-                    variant_name.len(),
-                    // FIXME: what if enumeration has i128 discriminant?
-                    discr.val as i64,
-                    is_unsigned,
-                ))
-            }
+    let enumerator_di_nodes: SmallVec<Option<&'ll DIType>> = enumerators
+        .map(|(name, value)| unsafe {
+            Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+                DIB(cx),
+                name.as_ptr().cast(),
+                name.len(),
+                value as i64,
+                is_unsigned,
+            ))
         })
         .collect();
 
@@ -247,23 +246,27 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
 /// and a DW_TAG_member for each field (but not the discriminant).
 fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
-    enum_type: Ty<'tcx>,
+    enum_type_and_layout: TyAndLayout<'tcx>,
     enum_type_di_node: &'ll DIType,
     variant_index: VariantIdx,
     variant_def: &VariantDef,
     variant_layout: TyAndLayout<'tcx>,
 ) -> &'ll DIType {
-    debug_assert_eq!(variant_layout.ty, enum_type);
+    debug_assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
 
     type_map::build_type_with_children(
         cx,
         type_map::stub(
             cx,
             Stub::Struct,
-            UniqueTypeId::for_enum_variant_struct_type(cx.tcx, enum_type, variant_index),
+            UniqueTypeId::for_enum_variant_struct_type(
+                cx.tcx,
+                enum_type_and_layout.ty,
+                variant_index,
+            ),
             variant_def.name.as_str(),
             // NOTE: We use size and align of enum_type, not from variant_layout:
-            cx.size_and_align_of(enum_type),
+            size_and_align_of(enum_type_and_layout),
             Some(enum_type_di_node),
             DIFlags::FlagZero,
         ),
@@ -290,9 +293,9 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
                         type_di_node(cx, field_layout.ty),
                     )
                 })
-                .collect()
+                .collect::<SmallVec<_>>()
         },
-        |cx| build_generic_type_param_di_nodes(cx, enum_type),
+        |cx| build_generic_type_param_di_nodes(cx, enum_type_and_layout.ty),
     )
     .di_node
 }
@@ -398,6 +401,19 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>(
     .di_node
 }
 
+#[derive(Copy, Clone)]
+enum DiscrResult {
+    NoDiscriminant,
+    Value(u128),
+    Range(u128, u128),
+}
+
+impl DiscrResult {
+    fn opt_single_val(&self) -> Option<u128> {
+        if let Self::Value(d) = *self { Some(d) } else { None }
+    }
+}
+
 /// Returns the discriminant value corresponding to the variant index.
 ///
 /// Will return `None` if there is less than two variants (because then the enum won't have)
@@ -407,12 +423,11 @@ fn compute_discriminant_value<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     enum_type_and_layout: TyAndLayout<'tcx>,
     variant_index: VariantIdx,
-) -> Option<u64> {
+) -> DiscrResult {
     match enum_type_and_layout.layout.variants() {
-        &Variants::Single { .. } => None,
-        &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => Some(
-            enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val
-                as u64,
+        &Variants::Single { .. } => DiscrResult::NoDiscriminant,
+        &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
+            enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
         ),
         &Variants::Multiple {
             tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
@@ -420,17 +435,26 @@ fn compute_discriminant_value<'ll, 'tcx>(
             ..
         } => {
             if variant_index == dataful_variant {
-                None
+                let valid_range = enum_type_and_layout
+                    .for_variant(cx, variant_index)
+                    .largest_niche
+                    .as_ref()
+                    .unwrap()
+                    .valid_range;
+
+                let min = valid_range.start.min(valid_range.end);
+                let min = tag.size(cx).truncate(min);
+
+                let max = valid_range.start.max(valid_range.end);
+                let max = tag.size(cx).truncate(max);
+
+                DiscrResult::Range(min, max)
             } else {
                 let value = (variant_index.as_u32() as u128)
                     .wrapping_sub(niche_variants.start().as_u32() as u128)
                     .wrapping_add(niche_start);
                 let value = tag.size(cx).truncate(value);
-                // NOTE(eddyb) do *NOT* remove this assert, until
-                // we pass the full 128-bit value to LLVM, otherwise
-                // truncation will be silent and remain undetected.
-                assert_eq!(value as u64 as u128, value);
-                Some(value as u64)
+                DiscrResult::Value(value)
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index f1935e0ec31..dae90a43f26 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -88,7 +88,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
                     variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
                     variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node(
                         cx,
-                        enum_type,
+                        enum_type_and_layout,
                         enum_type_di_node,
                         variant_index,
                         enum_adt_def.variant(variant_index),
@@ -413,7 +413,13 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
             enum_type_and_layout.size.bits(),
             enum_type_and_layout.align.abi.bits() as u32,
             Size::ZERO.bits(),
-            discr_value.map(|v| cx.const_u64(v)),
+            discr_value.opt_single_val().map(|value| {
+                // NOTE(eddyb) do *NOT* remove this assert, until
+                // we pass the full 128-bit value to LLVM, otherwise
+                // truncation will be silent and remain undetected.
+                assert_eq!(value as u64 as u128, value);
+                cx.const_u64(value as u64)
+            }),
             DIFlags::FlagZero,
             variant_member_info.variant_struct_type_di_node,
         )
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index ce2f419c4ac..e30622cbdce 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -47,6 +47,8 @@ pub(super) enum UniqueTypeId<'tcx> {
     VariantPart(Ty<'tcx>, private::HiddenZst),
     /// The ID for the artificial struct type describing a single enum variant.
     VariantStructType(Ty<'tcx>, VariantIdx, private::HiddenZst),
+    /// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode.
+    VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst),
     /// The ID of the artificial type we create for VTables.
     VTableTy(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>, private::HiddenZst),
 }
@@ -71,6 +73,15 @@ impl<'tcx> UniqueTypeId<'tcx> {
         UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst)
     }
 
+    pub fn for_enum_variant_struct_type_wrapper(
+        tcx: TyCtxt<'tcx>,
+        enum_ty: Ty<'tcx>,
+        variant_idx: VariantIdx,
+    ) -> Self {
+        debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst)
+    }
+
     pub fn for_vtable_ty(
         tcx: TyCtxt<'tcx>,
         self_type: Ty<'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 3139f93bfef..89611fc0dee 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2079,6 +2079,19 @@ extern "C" {
         Ty: &'a DIType,
     ) -> &'a DIType;
 
+    pub fn LLVMRustDIBuilderCreateStaticMemberType<'a>(
+        Builder: &DIBuilder<'a>,
+        Scope: &'a DIDescriptor,
+        Name: *const c_char,
+        NameLen: size_t,
+        File: &'a DIFile,
+        LineNo: c_uint,
+        Ty: &'a DIType,
+        Flags: DIFlags,
+        val: Option<&'a Value>,
+        AlignInBits: u32,
+    ) -> &'a DIDerivedType;
+
     pub fn LLVMRustDIBuilderCreateLexicalBlock<'a>(
         Builder: &DIBuilder<'a>,
         Scope: &'a DIScope,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 8cd5a0fc247..1dde6ae8edf 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -18,11 +18,10 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
-use rustc_target::abi::{Integer, TagEncoding, Variants};
+use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
+use rustc_target::abi::Integer;
 use smallvec::SmallVec;
 
-use std::borrow::Cow;
 use std::fmt::Write;
 
 use crate::debuginfo::wants_c_like_enum_debuginfo;
@@ -98,7 +97,6 @@ fn push_debuginfo_type_name<'tcx>(
 
             if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
                 msvc_enum_fallback(
-                    tcx,
                     ty_and_layout,
                     &|output, visited| {
                         push_item_name(tcx, def.did(), true, output);
@@ -395,7 +393,6 @@ fn push_debuginfo_type_name<'tcx>(
             if cpp_like_debuginfo && t.is_generator() {
                 let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
                 msvc_enum_fallback(
-                    tcx,
                     ty_and_layout,
                     &|output, visited| {
                         push_closure_or_generator_name(tcx, def_id, substs, true, output, visited);
@@ -428,58 +425,17 @@ fn push_debuginfo_type_name<'tcx>(
 
     /// MSVC names enums differently than other platforms so that the debugging visualization
     // format (natvis) is able to understand enums and render the active variant correctly in the
-    // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
-    // `EnumMemberDescriptionFactor::create_member_descriptions`.
+    // debugger. For more information, look in
+    // rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
     fn msvc_enum_fallback<'tcx>(
-        tcx: TyCtxt<'tcx>,
         ty_and_layout: TyAndLayout<'tcx>,
         push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
         output: &mut String,
         visited: &mut FxHashSet<Ty<'tcx>>,
     ) {
         debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
-        let ty = ty_and_layout.ty;
-
         output.push_str("enum$<");
         push_inner(output, visited);
-
-        let variant_name = |variant_index| match ty.kind() {
-            ty::Adt(adt_def, _) => {
-                debug_assert!(adt_def.is_enum());
-                Cow::from(adt_def.variant(variant_index).name.as_str())
-            }
-            ty::Generator(..) => GeneratorSubsts::variant_name(variant_index),
-            _ => unreachable!(),
-        };
-
-        if let Variants::Multiple {
-            tag_encoding: TagEncoding::Niche { dataful_variant, .. },
-            tag,
-            variants,
-            ..
-        } = &ty_and_layout.variants
-        {
-            let dataful_variant_layout = &variants[*dataful_variant];
-
-            // calculate the range of values for the dataful variant
-            let dataful_discriminant_range =
-                dataful_variant_layout.largest_niche().unwrap().valid_range;
-
-            let min = dataful_discriminant_range.start;
-            let min = tag.size(&tcx).truncate(min);
-
-            let max = dataful_discriminant_range.end;
-            let max = tag.size(&tcx).truncate(max);
-
-            let dataful_variant_name = variant_name(*dataful_variant);
-            write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap();
-        } else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants {
-            // Uninhabited enums can't be constructed and should never need to be visualized so
-            // skip this step for them.
-            if !ty_and_layout.abi.is_uninhabited() {
-                write!(output, ", {}", variant_name(*variant_idx)).unwrap();
-            }
-        }
         push_close_angle_bracket(true, output);
     }
 
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 30ff364210d..4172ce3bb30 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -172,7 +172,9 @@ impl<I: Idx, T> IndexVec<I, T> {
     }
 
     #[inline]
-    pub fn indices(&self) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + 'static {
+    pub fn indices(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + Clone + 'static {
         (0..self.len()).map(|n| I::new(n))
     }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 5f5b5de790e..f9bffe6d823 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -924,6 +924,30 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
                                                fromRust(Flags), unwrapDI<DIType>(Ty)));
 }
 
+extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType(
+    LLVMRustDIBuilderRef Builder,
+    LLVMMetadataRef Scope,
+    const char *Name,
+    size_t NameLen,
+    LLVMMetadataRef File,
+    unsigned LineNo,
+    LLVMMetadataRef Ty,
+    LLVMRustDIFlags Flags,
+    LLVMValueRef val,
+    uint32_t AlignInBits
+) {
+  return wrap(Builder->createStaticMemberType(
+    unwrapDI<DIDescriptor>(Scope),
+    StringRef(Name, NameLen),
+    unwrapDI<DIFile>(File),
+    LineNo,
+    unwrapDI<DIType>(Ty),
+    fromRust(Flags),
+    unwrap<llvm::ConstantInt>(val),
+    AlignInBits
+  ));
+}
+
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
     LLVMMetadataRef File, unsigned Line, unsigned Col) {
diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis
index 558536fa613..9f1aa525d1f 100644
--- a/src/etc/natvis/intrinsic.natvis
+++ b/src/etc/natvis/intrinsic.natvis
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
   <Type Name="str">
     <DisplayString>{(char*)data_ptr,[length]s8}</DisplayString>
@@ -150,76 +150,122 @@
     </Expand>
   </Type>
 
-  <!-- Directly tagged enums. $T1 is the type name -->
+  <!--
+    This is the visualizer for all enums. It takes care of selecting the active variant.
+    See `compiler\rustc_codegen_llvm\src\debuginfo\metadata\enums\cpp_like.rs` for more information.
+  -->
   <Type Name="enum$&lt;*&gt;">
-    <Intrinsic Name="tag" Expression="discriminant" />
-    <DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString>
-    <DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
+    <Intrinsic Name="in_range" Expression="(start &lt;= end) ? ((tag &gt;= start) &amp;&amp; (tag &lt;= end)) : ((tag &gt;= start) || (tag &lt;= end))">
+      <Parameter Name="start" Type="unsigned __int64" />
+      <Parameter Name="end" Type="unsigned __int64" />
+    </Intrinsic>
 
-    <Expand>
-      <Synthetic Name="[variant]">
-        <DisplayString>{tag(),en}</DisplayString>
-      </Synthetic>
-      <ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
-      <ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
-      <ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
-      <ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem>
-      <ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem>
-      <ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem>
-      <ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem>
-      <ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem>
-      <ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem>
-      <ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem>
-      <ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem>
-      <ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem>
-      <ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem>
-      <ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem>
-      <ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem>
-      <ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem>
-    </Expand>
-  </Type>
+    <Intrinsic Name="exact_match128" Expression="(tag128_hi == discr_hi) &amp;&amp; (tag128_lo == discr_lo)">
+      <Parameter Name="discr_hi" Type="unsigned __int64" />
+      <Parameter Name="discr_lo" Type="unsigned __int64" />
+    </Intrinsic>
 
-  <!-- Single variant enums. $T1 is the name of the enum, $T2 is the name of the variant -->
-  <Type Name="enum$&lt;*, *&gt;">
-    <DisplayString>{"$T2",sb}</DisplayString>
-    <Expand>
-      <Synthetic Name="[variant]">
-        <DisplayString>{"$T2",sb}</DisplayString>
-      </Synthetic>
-      <ExpandedItem>$T2</ExpandedItem>
-    </Expand>
-  </Type>
+    <Intrinsic Name="lt128" Expression="(x_hi &lt; y_hi) || ((x_hi == y_hi) &amp;&amp; (x_lo &lt; y_lo))">
+      <Parameter Name="x_hi" Type="unsigned __int64" />
+      <Parameter Name="x_lo" Type="unsigned __int64" />
+      <Parameter Name="y_hi" Type="unsigned __int64" />
+      <Parameter Name="y_lo" Type="unsigned __int64" />
+    </Intrinsic>
 
-  <!-- Niche-layout enums. $T1 is the name of the enum, $T2 is the low value of the dataful
-       variant tag, $T3 is the high value of the dataful variant tag, $T4 is the name of
-       the dataful variant -->
-  <Type Name="enum$&lt;*, *, *, *&gt;">
-    <Intrinsic Name="tag" Expression="discriminant" />
-    <Intrinsic Name="is_dataful" Expression="tag() &gt;= $T2 &amp;&amp; tag() &lt;= $T3" />
-    <DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString>
-    <DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString>
-    <Expand>
-      <ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem>
-      <Synthetic Condition="is_dataful()" Name="[variant]">
-        <DisplayString>{"$T4",sb}</DisplayString>
-      </Synthetic>
-      <Synthetic Condition="!is_dataful()" Name="[variant]">
-        <DisplayString>{discriminant,en}</DisplayString>
-      </Synthetic>
+    <Intrinsic Name="lt_or_eq128" Expression="((x_hi == y_hi) &amp;&amp; (x_lo == y_lo)) || lt128(x_hi, x_lo, y_hi, y_lo)">
+      <Parameter Name="x_hi" Type="unsigned __int64" />
+      <Parameter Name="x_lo" Type="unsigned __int64" />
+      <Parameter Name="y_hi" Type="unsigned __int64" />
+      <Parameter Name="y_lo" Type="unsigned __int64" />
+    </Intrinsic>
+
+    <Intrinsic Name="in_range128" Expression="lt_or_eq128(begin_hi, begin_lo, tag128_hi, tag128_lo) &amp;&amp; lt_or_eq128(tag128_hi, tag128_lo, end_hi, end_lo)">
+      <Parameter Name="begin_hi" Type="unsigned __int64" />
+      <Parameter Name="begin_lo" Type="unsigned __int64" />
+      <Parameter Name="end_hi" Type="unsigned __int64" />
+      <Parameter Name="end_lo" Type="unsigned __int64" />
+    </Intrinsic>
+
+    <DisplayString Condition="tag == variant0.DISCR_EXACT" Optional="true">{variant0.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant1.DISCR_EXACT" Optional="true">{variant1.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant2.DISCR_EXACT" Optional="true">{variant2.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant3.DISCR_EXACT" Optional="true">{variant3.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant4.DISCR_EXACT" Optional="true">{variant4.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant5.DISCR_EXACT" Optional="true">{variant5.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant6.DISCR_EXACT" Optional="true">{variant6.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant7.DISCR_EXACT" Optional="true">{variant7.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant8.DISCR_EXACT" Optional="true">{variant8.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant9.DISCR_EXACT" Optional="true">{variant9.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant10.DISCR_EXACT" Optional="true">{variant10.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant11.DISCR_EXACT" Optional="true">{variant11.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant12.DISCR_EXACT" Optional="true">{variant12.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant13.DISCR_EXACT" Optional="true">{variant13.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant14.DISCR_EXACT" Optional="true">{variant14.NAME,en}</DisplayString>
+    <DisplayString Condition="tag == variant15.DISCR_EXACT" Optional="true">{variant15.NAME,en}</DisplayString>
+
+    <DisplayString Condition="in_range(variant_fallback.DISCR_BEGIN, variant_fallback.DISCR_END)" Optional="true">{variant_fallback.NAME,en}</DisplayString>
+
+    <DisplayString Condition="exact_match128(variant0.DISCR128_EXACT_HI, variant0.DISCR128_EXACT_LO)" Optional="true">{variant0.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant1.DISCR128_EXACT_HI, variant1.DISCR128_EXACT_LO)" Optional="true">{variant1.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant2.DISCR128_EXACT_HI, variant2.DISCR128_EXACT_LO)" Optional="true">{variant2.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant3.DISCR128_EXACT_HI, variant3.DISCR128_EXACT_LO)" Optional="true">{variant3.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant4.DISCR128_EXACT_HI, variant4.DISCR128_EXACT_LO)" Optional="true">{variant4.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant5.DISCR128_EXACT_HI, variant5.DISCR128_EXACT_LO)" Optional="true">{variant5.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant6.DISCR128_EXACT_HI, variant6.DISCR128_EXACT_LO)" Optional="true">{variant6.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant7.DISCR128_EXACT_HI, variant7.DISCR128_EXACT_LO)" Optional="true">{variant7.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant8.DISCR128_EXACT_HI, variant8.DISCR128_EXACT_LO)" Optional="true">{variant8.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant9.DISCR128_EXACT_HI, variant9.DISCR128_EXACT_LO)" Optional="true">{variant9.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant10.DISCR128_EXACT_HI, variant10.DISCR128_EXACT_LO)" Optional="true">{variant10.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant11.DISCR128_EXACT_HI, variant11.DISCR128_EXACT_LO)" Optional="true">{variant11.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant12.DISCR128_EXACT_HI, variant12.DISCR128_EXACT_LO)" Optional="true">{variant12.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant13.DISCR128_EXACT_HI, variant13.DISCR128_EXACT_LO)" Optional="true">{variant13.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant14.DISCR128_EXACT_HI, variant14.DISCR128_EXACT_LO)" Optional="true">{variant14.NAME,en}</DisplayString>
+    <DisplayString Condition="exact_match128(variant15.DISCR128_EXACT_HI, variant15.DISCR128_EXACT_LO)" Optional="true">{variant15.NAME,en}</DisplayString>
+
+    <DisplayString
+      Condition="in_range128(variant_fallback.DISCR128_BEGIN_HI, variant_fallback.DISCR128_BEGIN_LO, variant_fallback.DISCR128_END_HI, variant_fallback.DISCR128_END_LO)"
+      Optional="true">{variant_fallback.NAME,en}</DisplayString>
+
+    <Expand HideRawView="true">
+      <ExpandedItem Condition="tag == variant0.DISCR_EXACT" Optional="true">variant0.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant1.DISCR_EXACT" Optional="true">variant1.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant2.DISCR_EXACT" Optional="true">variant2.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant3.DISCR_EXACT" Optional="true">variant3.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant4.DISCR_EXACT" Optional="true">variant4.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant5.DISCR_EXACT" Optional="true">variant5.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant6.DISCR_EXACT" Optional="true">variant6.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant7.DISCR_EXACT" Optional="true">variant7.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant8.DISCR_EXACT" Optional="true">variant8.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant9.DISCR_EXACT" Optional="true">variant9.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant10.DISCR_EXACT" Optional="true">variant10.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant11.DISCR_EXACT" Optional="true">variant11.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant12.DISCR_EXACT" Optional="true">variant12.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant13.DISCR_EXACT" Optional="true">variant13.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant14.DISCR_EXACT" Optional="true">variant14.value</ExpandedItem>
+      <ExpandedItem Condition="tag == variant15.DISCR_EXACT" Optional="true">variant15.value</ExpandedItem>
+
+      <ExpandedItem Condition="in_range(variant_fallback.DISCR_BEGIN, variant_fallback.DISCR_END)" Optional="true">variant_fallback.value</ExpandedItem>
+
+      <ExpandedItem Condition="exact_match128(variant0.DISCR128_EXACT_HI, variant0.DISCR128_EXACT_LO)" Optional="true">variant0.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant1.DISCR128_EXACT_HI, variant1.DISCR128_EXACT_LO)" Optional="true">variant1.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant2.DISCR128_EXACT_HI, variant2.DISCR128_EXACT_LO)" Optional="true">variant2.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant3.DISCR128_EXACT_HI, variant3.DISCR128_EXACT_LO)" Optional="true">variant3.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant4.DISCR128_EXACT_HI, variant4.DISCR128_EXACT_LO)" Optional="true">variant4.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant5.DISCR128_EXACT_HI, variant5.DISCR128_EXACT_LO)" Optional="true">variant5.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant6.DISCR128_EXACT_HI, variant6.DISCR128_EXACT_LO)" Optional="true">variant6.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant7.DISCR128_EXACT_HI, variant7.DISCR128_EXACT_LO)" Optional="true">variant7.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant8.DISCR128_EXACT_HI, variant8.DISCR128_EXACT_LO)" Optional="true">variant8.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant9.DISCR128_EXACT_HI, variant9.DISCR128_EXACT_LO)" Optional="true">variant9.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant10.DISCR128_EXACT_HI, variant10.DISCR128_EXACT_LO)" Optional="true">variant10.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant11.DISCR128_EXACT_HI, variant11.DISCR128_EXACT_LO)" Optional="true">variant11.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant12.DISCR128_EXACT_HI, variant12.DISCR128_EXACT_LO)" Optional="true">variant12.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant13.DISCR128_EXACT_HI, variant13.DISCR128_EXACT_LO)" Optional="true">variant13.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant14.DISCR128_EXACT_HI, variant14.DISCR128_EXACT_LO)" Optional="true">variant14.value</ExpandedItem>
+      <ExpandedItem Condition="exact_match128(variant15.DISCR128_EXACT_HI, variant15.DISCR128_EXACT_LO)" Optional="true">variant15.value</ExpandedItem>
+
+      <ExpandedItem
+        Condition="in_range128(variant_fallback.DISCR128_BEGIN_HI, variant_fallback.DISCR128_BEGIN_LO, variant_fallback.DISCR128_END_HI, variant_fallback.DISCR128_END_LO)"
+        Optional="true">variant_fallback.value</ExpandedItem>
     </Expand>
   </Type>
 </AutoVisualizer>
diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs
index d6d7e5b44aa..95b0819cc38 100644
--- a/src/test/debuginfo/generator-objects.rs
+++ b/src/test/debuginfo/generator-objects.rs
@@ -42,13 +42,11 @@
 // cdb-command: g
 // cdb-command: dx b
 // cdb-check: b                : Unresumed [Type: enum$<generator_objects::main::generator_env$0>]
-// cdb-check:    [variant]        : Unresumed
 // cdb-check:    [+0x[...]] _ref__a          : 0x[...] : 5 [Type: int *]
 
 // cdb-command: g
 // cdb-command: dx b
 // cdb-check: b                : Suspend0 [Type: enum$<generator_objects::main::generator_env$0>]
-// cdb-check:    [variant]        : Suspend0
 // cdb-check:    [+0x[...]] c                : 6 [Type: int]
 // cdb-check:    [+0x[...]] d                : 7 [Type: int]
 // cdb-check:    [+0x[...]] _ref__a          : 0x[...] : 5 [Type: int *]
@@ -56,7 +54,6 @@
 // cdb-command: g
 // cdb-command: dx b
 // cdb-check: b                : Suspend1 [Type: enum$<generator_objects::main::generator_env$0>]
-// cdb-check:    [variant]        : Suspend1
 // cdb-check:    [+0x[...]] c                : 7 [Type: int]
 // cdb-check:    [+0x[...]] d                : 8 [Type: int]
 // cdb-check:    [+0x[...]] _ref__a          : 0x[...] : 6 [Type: int *]
@@ -64,8 +61,6 @@
 // cdb-command: g
 // cdb-command: dx b
 // cdb-check: b                : Returned [Type: enum$<generator_objects::main::generator_env$0>]
-// cdb-check:    [<Raw View>]     [Type: enum$<generator_objects::main::generator_env$0>]
-// cdb-check:    [variant]        : Returned
 // cdb-check:    [+0x[...]] _ref__a          : 0x[...] : 6 [Type: int *]
 
 #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs
index a153a9a4228..b1ca5dfa1c7 100644
--- a/src/test/debuginfo/msvc-pretty-enums.rs
+++ b/src/test/debuginfo/msvc-pretty-enums.rs
@@ -4,69 +4,110 @@
 // cdb-command: g
 
 // cdb-command: dx a
-// cdb-check:a                :  Some({...}) [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
-// cdb-check:    [variant]        :  Some
+// cdb-check:a                : Some [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum> >]
 // cdb-check:    [+0x000] __0              : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
 
 // cdb-command: dx b
-// cdb-check:b                : None [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
-// cdb-check:    [variant]        : None
+// cdb-check:b                : None [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum> >]
 
 // cdb-command: dx c
-// cdb-check:c                : Tag1 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [variant]        : Tag1
+// cdb-check:c                : Tag1 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum>]
 
 // cdb-command: dx d
-// cdb-check:d                :  Data({...}) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [variant]        :  Data
+// cdb-check:d                : Data [Type: enum$<msvc_pretty_enums::NicheLayoutEnum>]
 // cdb-check:    [+0x000] my_data          : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
 
 // cdb-command: dx e
-// cdb-check:e                : Tag2 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [variant]        : Tag2
+// cdb-check:e                : Tag2 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum>]
 
 // cdb-command: dx f
-// cdb-check:f                :  Some({...}) [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
-// cdb-check:    [variant]        :  Some
+// cdb-check:f                : Some [Type: enum$<core::option::Option<ref$<u32> > >]
 // cdb-check:    [+0x000] __0              : 0x[...] : 0x1 [Type: unsigned int *]
 
 // cdb-command: dx g
-// cdb-check:g                : None [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
-// cdb-check:    [variant]        : None
+// cdb-check:g                : None [Type: enum$<core::option::Option<ref$<u32> > >]
 
 // cdb-command: dx h
 // cdb-check:h                : Some [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [variant]        : Some
 // cdb-check:    [+0x004] __0              : 0xc [Type: unsigned int]
 
 // cdb-command: dx i
 // cdb-check:i                : None [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [variant]        : None
 
 // cdb-command: dx j
 // cdb-check:j                : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
 
 // cdb-command: dx k
-// cdb-check:k                :  Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
-// cdb-check:    [variant]        :  Some
+// cdb-check:k                : Some [Type: enum$<core::option::Option<alloc::string::String> >]
 // cdb-check:    [+0x000] __0              : "IAMA optional string!" [Type: alloc::string::String]
 
 // cdb-command: dx l
-// cdb-check:l                :  Ok [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
-// cdb-check:    [variant]        :  Ok
+// cdb-check:l                : Ok [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> > >]
 // cdb-check:    [+0x000] __0              : 0x2a [Type: unsigned int]
 
+// cdb-command: dx niche128_some
+// cdb-check:niche128_some    : Some [Type: enum$<core::option::Option<core::num::nonzero::NonZeroI128> >]
+// Note: we can't actually read the value of the field because CDB cannot handle 128 bit integers.
+// cdb-check:    [+0x000] __0 [...] [Type: core::num::nonzero::NonZeroI128]
+
+// cdb-command: dx niche128_none
+// cdb-check: niche128_none    : None [Type: enum$<core::option::Option<core::num::nonzero::NonZeroI128> >]
+
+// cdb-command: dx niche_w_fields_1_some,d
+// cdb-check: niche_w_fields_1_some,d : A [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields1>]
+// cdb-check:     [+0x[...]] __0              : 0x[...] : 77 [Type: unsigned char *]
+// cdb-check:     [+0x[...]] __1              : 7 [Type: unsigned int]
+
+// cdb-command: dx niche_w_fields_1_none,d
+// cdb-check: niche_w_fields_1_none,d : B [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields1>]
+// cdb-check:     [+0x[...]] __0              : 99 [Type: unsigned int]
+
+// cdb-command: dx niche_w_fields_2_some,d
+// cdb-check: niche_w_fields_2_some,d : A [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields2>]
+// cdb-check:     [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields2>]
+// cdb-check:     [+0x[...]] __0              : 800 [Type: core::num::nonzero::NonZeroU32]
+// cdb-check:     [+0x[...]] __1              : 900 [Type: unsigned __int64]
+
+// cdb-command: dx niche_w_fields_2_none,d
+// cdb-check: niche_w_fields_2_none,d : B [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields2>]
+// cdb-check:     [+0x[...]] __0              : 1000 [Type: unsigned __int64]
+
+// cdb-command: dx niche_w_fields_3_some,d
+// cdb-check: niche_w_fields_3_some,d : A [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields3>]
+// cdb-check:     [+0x[...]] __0              : 137 [Type: unsigned char]
+// cdb-check:     [+0x[...]] __1              : true [Type: bool]
+
+// cdb-command: dx niche_w_fields_3_niche1,d
+// cdb-check: niche_w_fields_3_niche1,d : B [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields3>]
+// cdb-check:     [+0x[...]] __0              : 12 [Type: unsigned char]
+
+// cdb-command: dx niche_w_fields_3_niche2,d
+// cdb-check: niche_w_fields_3_niche2,d : C [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields3>]
+// cdb-check:     [+0x[...]] __0              : false [Type: bool]
+
+// cdb-command: dx niche_w_fields_3_niche3,d
+// cdb-check: niche_w_fields_3_niche3,d : D [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields3>]
+// cdb-check:     [+0x[...]] __0              : 34 [Type: unsigned char]
+
+// cdb-command: dx niche_w_fields_3_niche4,d
+// cdb-check: niche_w_fields_3_niche4,d : E [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields3>]
+// cdb-check:     [+0x[...]] __0              : 56 [Type: unsigned char]
+
+// cdb-command: dx niche_w_fields_3_niche5,d
+// cdb-check: niche_w_fields_3_niche5,d : F [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields3>]
+
+// cdb-command: dx -r3 niche_w_fields_std_result_ok,d
+// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum$<core::result::Result<alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>,u64> >]
+// cdb-check:    [+0x[...]] __0              [Type: alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>]
+// cdb-check:        [+0x[...]] data_ptr         : [...]
+// cdb-check:        [+0x[...]] length           : 3 [...]
+
+// cdb-command: dx -r3 niche_w_fields_std_result_err,d
+// cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum$<core::result::Result<alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>,u64> >]
+// cdb-check:    [+0x[...]] __0              : 789 [Type: unsigned __int64]
+
+use std::num::{NonZeroI128, NonZeroU32};
+
 pub enum CStyleEnum {
     Low = 2,
     High = 16,
@@ -80,6 +121,27 @@ pub enum NicheLayoutEnum {
 
 pub enum Empty {}
 
+// The following three types will use a niche layout once
+// https://github.com/rust-lang/rust/pull/94075 is merged:
+enum NicheLayoutWithFields1<'a> {
+    A(&'a u8, u32),
+    B(u32),
+}
+
+enum NicheLayoutWithFields2 {
+    A(NonZeroU32, usize),
+    B(usize),
+}
+
+enum NicheLayoutWithFields3 {
+    A(u8, bool),
+    B(u8),
+    C(bool),
+    D(u8),
+    E(u8),
+    F,
+}
+
 fn main() {
     let a = Some(CStyleEnum::Low);
     let b = Option::<CStyleEnum>::None;
@@ -93,6 +155,24 @@ fn main() {
     let j = CStyleEnum::High;
     let k = Some("IAMA optional string!".to_string());
     let l = Result::<u32, Empty>::Ok(42);
+    let niche128_some = Some(NonZeroI128::new(123456).unwrap());
+    let niche128_none: Option<NonZeroI128> = None;
+
+    let niche_w_fields_1_some = NicheLayoutWithFields1::A(&77, 7);
+    let niche_w_fields_1_none = NicheLayoutWithFields1::B(99);
+
+    let niche_w_fields_2_some = NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900);
+    let niche_w_fields_2_none = NicheLayoutWithFields2::B(1000);
+
+    let niche_w_fields_3_some = NicheLayoutWithFields3::A(137, true);
+    let niche_w_fields_3_niche1 = NicheLayoutWithFields3::B(12);
+    let niche_w_fields_3_niche2 = NicheLayoutWithFields3::C(false);
+    let niche_w_fields_3_niche3 = NicheLayoutWithFields3::D(34);
+    let niche_w_fields_3_niche4 = NicheLayoutWithFields3::E(56);
+    let niche_w_fields_3_niche5 = NicheLayoutWithFields3::F;
+
+    let niche_w_fields_std_result_ok: Result<Box<[u8]>, u64> = Ok(vec![1, 2, 3].into());
+    let niche_w_fields_std_result_err: Result<Box<[u8]>, u64> = Err(789);
 
     zzz(); // #break
 }
diff --git a/src/test/debuginfo/msvc-scalarpair-params.rs b/src/test/debuginfo/msvc-scalarpair-params.rs
index 3846fb42f81..38a9633c9bf 100644
--- a/src/test/debuginfo/msvc-scalarpair-params.rs
+++ b/src/test/debuginfo/msvc-scalarpair-params.rs
@@ -19,11 +19,9 @@
 
 // cdb-command: dx o1
 // cdb-check:o1               : Some [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [variant]        : Some
 // cdb-check:    [+0x004] __0              : 0x4d2 [Type: [...]]
 // cdb-command: dx o2
 // cdb-check:o2               : Some [Type: enum$<core::option::Option<u64> >]
-// cdb-check:    [variant]        : Some
 // cdb-check:    [+0x008] __0              : 0x162e [Type: unsigned __int64]
 
 // cdb-command: g
@@ -89,7 +87,7 @@ fn slice(s: &[u8]) {
     zzz(); // #break
 }
 
-fn zzz() { }
+fn zzz() {}
 
 fn main() {
     range(10..12, 20..30);
diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs
index 55a4ecc1c1a..fe44c42aa53 100644
--- a/src/test/debuginfo/pretty-std.rs
+++ b/src/test/debuginfo/pretty-std.rs
@@ -39,7 +39,6 @@
 // gdb-command: print some_string
 // gdb-check:$8 = Some = {"IAMA "...}
 
-
 // === LLDB TESTS ==================================================================================
 
 // lldb-command: run
@@ -65,7 +64,6 @@
 // lldb-command: print os_string
 // lldb-check:[...]$6 = "IAMA OS string 😃"[...]
 
-
 // === CDB TESTS ==================================================================================
 
 // cdb-command: g
@@ -120,18 +118,15 @@
 // cdb-command: dx some
 // cdb-check:some             : Some [Type: enum$<core::option::Option<i16> >]
 // cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<i16> >]
-// cdb-check:    [variant]        : Some
 // cdb-check:    [+0x002] __0              : 8 [Type: short]
 
 // cdb-command: dx none
 // cdb-check:none             : None [Type: enum$<core::option::Option<i64> >]
 // cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<i64> >]
-// cdb-check:    [variant]        : None
 
 // cdb-command: dx some_string
-// cdb-check:some_string      :  Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
-// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
-// cdb-check:    [variant]        :  Some
+// cdb-check:some_string      : Some [Type: enum$<core::option::Option<alloc::string::String> >]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<alloc::string::String> >]
 // cdb-check:    [+0x000] __0              : "IAMA optional string!" [Type: alloc::string::String]
 
 // cdb-command: dx linkedlist
@@ -153,7 +148,6 @@ use std::collections::{LinkedList, VecDeque};
 use std::ffi::OsString;
 
 fn main() {
-
     // &[]
     let slice: &[i32] = &[0, 1, 2, 3];
 
@@ -188,4 +182,6 @@ fn main() {
     zzz(); // #break
 }
 
-fn zzz() { () }
+fn zzz() {
+    ()
+}
diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs
index b040a6e7494..426d9ddf251 100644
--- a/src/test/debuginfo/type-names.rs
+++ b/src/test/debuginfo/type-names.rs
@@ -240,14 +240,14 @@
 // cdb-check:struct tuple$<usize (*)(f64),usize> rust_fn_with_return_value = [...]
 // cdb-check:struct tuple$<void (*)(enum$<core::result::Result<char,f64> >),usize> unsafe_fn = [...]
 // cdb-check:struct tuple$<void (*)(isize),usize> extern_c_fn = [...]
-// cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>),usize> rust_fn = [...]
+// cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> > >),usize> rust_fn = [...]
 // cdb-command:dv /t *_function*
 // cdb-check:struct tuple$<isize (*)(ptr_const$<u8>, ...),usize> variadic_function = [...]
 // cdb-check:struct tuple$<type_names::mod1::mod2::Struct3 (*)(type_names::mod1::mod2::Struct3),usize> generic_function_struct3 = [...]
 // cdb-check:struct tuple$<isize (*)(isize),usize> generic_function_int = [...]
 // cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn")
 // cdb-check:Return Type: void
-// cdb-check:Parameter Types: enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>
+// cdb-check:Parameter Types: enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> > >
 // cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn_with_return_value")
 // cdb-check:Return Type: usize
 // cdb-check:Parameter Types: f64