about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-30 23:36:10 +0000
committerbors <bors@rust-lang.org>2018-10-30 23:36:10 +0000
commit0db7abe5b6f3cdfca736f9238689cbea8ef61c7e (patch)
treeaf51f2a467017cf73d69494c03b524e61ba6d0ed /src
parent1cf82fd9c0e8eb9ff29d4165f9824c483bd72f7d (diff)
parent98b26888e552cf498518a6d34538302dc41ac6ae (diff)
downloadrust-0db7abe5b6f3cdfca736f9238689cbea8ef61c7e.tar.gz
rust-0db7abe5b6f3cdfca736f9238689cbea8ef61c7e.zip
Auto merge of #54004 - tromey:enum-debuginfo, r=tromey
Fix DWARF generation for enums

The DWARF generated for Rust enums was always somewhat unusual.
Rather than using DWARF constructs directly, it would emit magic field
names like "RUST$ENCODED$ENUM$0$Name" and "RUST$ENUM$DISR".  Since
PR #45225, though, even this has not worked -- the ad hoc scheme was
not updated to handle the wider variety of niche-filling layout
optimizations now available.

This patch changes the generated DWARF to use the standard tags meant
for this purpose; namely, DW_TAG_variant and DW_TAG_variant_part.

The patch to implement this went in to LLVM 7.  In order to work with
older versions of LLVM, and because LLVM doesn't do anything here for
PDB, the existing code is kept as a fallback mode.

Support for this DWARF is in the Rust lldb and in gdb 8.2.

Closes #32920
Closes #32924
Closes #52762
Closes #53153
Diffstat (limited to 'src')
-rw-r--r--src/ci/docker/x86_64-gnu/Dockerfile2
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs526
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs29
m---------src/llvm0
-rw-r--r--src/rustllvm/RustWrapper.cpp49
-rw-r--r--src/test/codegen/enum-debug-clike.rs35
-rw-r--r--src/test/codegen/enum-debug-niche.rs42
-rw-r--r--src/test/codegen/enum-debug-tagged.rs40
-rw-r--r--src/test/debuginfo/basic-types.rs4
-rw-r--r--src/test/debuginfo/borrowed-enum-legacy.rs94
-rw-r--r--src/test/debuginfo/borrowed-enum.rs17
-rw-r--r--src/test/debuginfo/cross-crate-spans.rs4
-rw-r--r--src/test/debuginfo/destructured-for-loop-variable.rs4
-rw-r--r--src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs115
-rw-r--r--src/test/debuginfo/generic-enum-with-different-disr-sizes.rs28
-rw-r--r--src/test/debuginfo/generic-struct-style-enum-legacy.rs96
-rw-r--r--src/test/debuginfo/generic-struct-style-enum.rs15
-rw-r--r--src/test/debuginfo/generic-tuple-style-enum-legacy.rs118
-rw-r--r--src/test/debuginfo/generic-tuple-style-enum.rs28
-rw-r--r--src/test/debuginfo/method-on-tuple-struct.rs10
-rw-r--r--src/test/debuginfo/nil-enum.rs13
-rw-r--r--src/test/debuginfo/recursive-struct-legacy.rs245
-rw-r--r--src/test/debuginfo/recursive-struct.rs19
-rw-r--r--src/test/debuginfo/struct-style-enum-legacy.rs115
-rw-r--r--src/test/debuginfo/struct-style-enum.rs22
-rw-r--r--src/test/debuginfo/tuple-style-enum-legacy.rs115
-rw-r--r--src/test/debuginfo/tuple-style-enum.rs22
-rw-r--r--src/test/debuginfo/unique-enum-legacy.rs98
-rw-r--r--src/test/debuginfo/unique-enum.rs18
-rw-r--r--src/test/debuginfo/vec-slices.rs2
-rw-r--r--src/tools/compiletest/src/header.rs23
m---------src/tools/lldb0
32 files changed, 1689 insertions, 259 deletions
diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile
index 444a8fe5da8..dd94f2652b4 100644
--- a/src/ci/docker/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/x86_64-gnu/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:16.04
+FROM ubuntu:18.10
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 846d5056411..ba1e3f5960c 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -31,9 +31,10 @@ use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
 use rustc::ich::NodeIdHashingMode;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc::ty::Instance;
-use common::CodegenCx;
+use common::{CodegenCx, C_u64};
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
-use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout};
+use rustc::ty::layout::{self, Align, HasDataLayout, Integer, IntegerExt, LayoutOf,
+                        PrimitiveExt, Size, TyLayout};
 use rustc::session::config;
 use rustc::util::nodemap::FxHashMap;
 use rustc_fs_util::path2cstr;
@@ -205,6 +206,7 @@ enum RecursiveTypeDescription<'ll, 'tcx> {
         unfinished_type: Ty<'tcx>,
         unique_type_id: UniqueTypeId,
         metadata_stub: &'ll DICompositeType,
+        member_holding_stub: &'ll DICompositeType,
         member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
     },
     FinalMetadata(&'ll DICompositeType)
@@ -215,6 +217,7 @@ fn create_and_register_recursive_type_forward_declaration(
     unfinished_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
     metadata_stub: &'ll DICompositeType,
+    member_holding_stub: &'ll DICompositeType,
     member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
 
@@ -227,6 +230,7 @@ fn create_and_register_recursive_type_forward_declaration(
         unfinished_type,
         unique_type_id,
         metadata_stub,
+        member_holding_stub,
         member_description_factory,
     }
 }
@@ -242,6 +246,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
                 unfinished_type,
                 unique_type_id,
                 metadata_stub,
+                member_holding_stub,
                 ref member_description_factory,
             } => {
                 // Make sure that we have a forward declaration of the type in
@@ -266,7 +271,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
 
                 // ... and attach them to the stub to complete it.
                 set_members_of_composite_type(cx,
-                                              metadata_stub,
+                                              member_holding_stub,
                                               member_descriptions);
                 return MetadataCreationResult::new(metadata_stub, true);
             }
@@ -350,6 +355,7 @@ fn vec_slice_metadata(
             size: pointer_size,
             align: pointer_align,
             flags: DIFlags::FlagZero,
+            discriminant: None,
         },
         MemberDescription {
             name: "length".to_owned(),
@@ -358,6 +364,7 @@ fn vec_slice_metadata(
             size: usize_size,
             align: usize_align,
             flags: DIFlags::FlagZero,
+            discriminant: None,
         },
     ];
 
@@ -458,6 +465,7 @@ fn trait_pointer_metadata(
             size: data_ptr_field.size,
             align: data_ptr_field.align,
             flags: DIFlags::FlagArtificial,
+            discriminant: None,
         },
         MemberDescription {
             name: "vtable".to_owned(),
@@ -466,6 +474,7 @@ fn trait_pointer_metadata(
             size: vtable_field.size,
             align: vtable_field.align,
             flags: DIFlags::FlagArtificial,
+            discriminant: None,
         },
     ];
 
@@ -914,6 +923,7 @@ struct MemberDescription<'ll> {
     size: Size,
     align: Align,
     flags: DIFlags,
+    discriminant: Option<u64>,
 }
 
 // A factory for MemberDescriptions. It produces a list of member descriptions
@@ -981,6 +991,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
                 size,
                 align,
                 flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1013,6 +1024,7 @@ fn prepare_struct_metadata(
         struct_type,
         unique_type_id,
         struct_metadata_stub,
+        struct_metadata_stub,
         StructMDF(StructMemberDescriptionFactory {
             ty: struct_type,
             variant,
@@ -1045,6 +1057,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
                 size,
                 align,
                 flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1059,15 +1072,18 @@ fn prepare_tuple_metadata(
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
 
+    let struct_stub = create_struct_stub(cx,
+                                         tuple_type,
+                                         &tuple_name[..],
+                                         unique_type_id,
+                                         NO_SCOPE_METADATA);
+
     create_and_register_recursive_type_forward_declaration(
         cx,
         tuple_type,
         unique_type_id,
-        create_struct_stub(cx,
-                           tuple_type,
-                           &tuple_name[..],
-                           unique_type_id,
-                           NO_SCOPE_METADATA),
+        struct_stub,
+        struct_stub,
         TupleMDF(TupleMemberDescriptionFactory {
             ty: tuple_type,
             component_types: component_types.to_vec(),
@@ -1099,6 +1115,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
                 size,
                 align,
                 flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1130,6 +1147,7 @@ fn prepare_union_metadata(
         union_type,
         unique_type_id,
         union_metadata_stub,
+        union_metadata_stub,
         UnionMDF(UnionMemberDescriptionFactory {
             layout: cx.layout_of(union_type),
             variant,
@@ -1142,6 +1160,20 @@ fn prepare_union_metadata(
 // Enums
 //=-----------------------------------------------------------------------------
 
+// DWARF variant support is only available starting in LLVM 7.
+// Although the earlier enum debug info output did not work properly
+// in all situations, it is better for the time being to continue to
+// sometimes emit the old style rather than emit something completely
+// useless when rust is compiled against LLVM 6 or older.  This
+// function decides which representation will be emitted.
+fn use_enum_fallback(cx: &CodegenCx) -> bool {
+    // On MSVC we have to use the fallback mode, because LLVM doesn't
+    // lower variant parts to PDB.
+    return cx.sess().target.target.options.is_like_msvc || unsafe {
+        llvm::LLVMRustVersionMajor() < 7
+    };
+}
+
 // Describes the members of an enum value: An enum is described as a union of
 // structs in DWARF. This MemberDescriptionFactory provides the description for
 // the members of this union; so for every variant of the given enum, this
@@ -1159,6 +1191,15 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
     fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
                                   -> Vec<MemberDescription<'ll>> {
         let adt = &self.enum_type.ty_adt_def().unwrap();
+
+        // This will always find the metadata in the type map.
+        let fallback = use_enum_fallback(cx);
+        let self_metadata = if fallback {
+            self.containing_scope
+        } else {
+            type_metadata(cx, self.enum_type, self.span)
+        };
+
         match self.layout.variants {
             layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
             layout::Variants::Single { index } => {
@@ -1167,7 +1208,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                           self.layout,
                                           &adt.variants[index],
                                           NoDiscriminant,
-                                          self.containing_scope,
+                                          self_metadata,
                                           self.span);
 
                 let member_descriptions =
@@ -1178,18 +1219,28 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                               member_descriptions);
                 vec![
                     MemberDescription {
-                        name: String::new(),
+                        name: if fallback {
+                            String::new()
+                        } else {
+                            adt.variants[index].name.as_str().to_string()
+                        },
                         type_metadata: variant_type_metadata,
                         offset: Size::ZERO,
                         size: self.layout.size,
                         align: self.layout.align,
-                        flags: DIFlags::FlagZero
+                        flags: DIFlags::FlagZero,
+                        discriminant: None,
                     }
                 ]
             }
             layout::Variants::Tagged { ref variants, .. } => {
-                let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
-                    .expect(""));
+                let discriminant_info = if fallback {
+                    RegularDiscriminant(self.discriminant_type_metadata
+                                        .expect(""))
+                } else {
+                    // This doesn't matter in this case.
+                    NoDiscriminant
+                };
                 (0..variants.len()).map(|i| {
                     let variant = self.layout.for_variant(cx, i);
                     let (variant_type_metadata, member_desc_factory) =
@@ -1197,7 +1248,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                               variant,
                                               &adt.variants[i],
                                               discriminant_info,
-                                              self.containing_scope,
+                                              self_metadata,
                                               self.span);
 
                     let member_descriptions = member_desc_factory
@@ -1207,75 +1258,127 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                                   variant_type_metadata,
                                                   member_descriptions);
                     MemberDescription {
-                        name: String::new(),
+                        name: if fallback {
+                            String::new()
+                        } else {
+                            adt.variants[i].name.as_str().to_string()
+                        },
                         type_metadata: variant_type_metadata,
                         offset: Size::ZERO,
-                        size: variant.size,
-                        align: variant.align,
-                        flags: DIFlags::FlagZero
+                        size: self.layout.size,
+                        align: self.layout.align,
+                        flags: DIFlags::FlagZero,
+                        discriminant: Some(self.layout.ty.ty_adt_def().unwrap()
+                                           .discriminant_for_variant(cx.tcx, i)
+                                           .val as u64),
                     }
                 }).collect()
             }
-            layout::Variants::NicheFilling { dataful_variant, ref niche_variants, .. } => {
-                let variant = self.layout.for_variant(cx, dataful_variant);
-                // Create a description of the non-null variant
-                let (variant_type_metadata, member_description_factory) =
-                    describe_enum_variant(cx,
-                                          variant,
-                                          &adt.variants[dataful_variant],
-                                          OptimizedDiscriminant,
-                                          self.containing_scope,
-                                          self.span);
+            layout::Variants::NicheFilling {
+                ref niche_variants,
+                niche_start,
+                ref variants,
+                dataful_variant,
+                ..
+            } => {
+                if fallback {
+                    let variant = self.layout.for_variant(cx, dataful_variant);
+                    // Create a description of the non-null variant
+                    let (variant_type_metadata, member_description_factory) =
+                        describe_enum_variant(cx,
+                                              variant,
+                                              &adt.variants[dataful_variant],
+                                              OptimizedDiscriminant,
+                                              self.containing_scope,
+                                              self.span);
 
-                let variant_member_descriptions =
-                    member_description_factory.create_member_descriptions(cx);
+                    let variant_member_descriptions =
+                        member_description_factory.create_member_descriptions(cx);
 
-                set_members_of_composite_type(cx,
-                                              variant_type_metadata,
-                                              variant_member_descriptions);
-
-                // Encode the information about the null variant in the union
-                // member's name.
-                let mut name = String::from("RUST$ENCODED$ENUM$");
-                // HACK(eddyb) the debuggers should just handle offset+size
-                // of discriminant instead of us having to recover its path.
-                // Right now it's not even going to work for `niche_start > 0`,
-                // and for multiple niche variants it only supports the first.
-                fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                                                name: &mut String,
-                                                layout: TyLayout<'tcx>,
-                                                offset: Size,
-                                                size: Size) {
-                    for i in 0..layout.fields.count() {
-                        let field_offset = layout.fields.offset(i);
-                        if field_offset > offset {
-                            continue;
-                        }
-                        let inner_offset = offset - field_offset;
-                        let field = layout.field(cx, i);
-                        if inner_offset + size <= field.size {
-                            write!(name, "{}$", i).unwrap();
-                            compute_field_path(cx, name, field, inner_offset, size);
+                    set_members_of_composite_type(cx,
+                                                  variant_type_metadata,
+                                                  variant_member_descriptions);
+
+                    // Encode the information about the null variant in the union
+                    // member's name.
+                    let mut name = String::from("RUST$ENCODED$ENUM$");
+                    // Right now it's not even going to work for `niche_start > 0`,
+                    // and for multiple niche variants it only supports the first.
+                    fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                                    name: &mut String,
+                                                    layout: TyLayout<'tcx>,
+                                                    offset: Size,
+                                                    size: Size) {
+                        for i in 0..layout.fields.count() {
+                            let field_offset = layout.fields.offset(i);
+                            if field_offset > offset {
+                                continue;
+                            }
+                            let inner_offset = offset - field_offset;
+                            let field = layout.field(cx, i);
+                            if inner_offset + size <= field.size {
+                                write!(name, "{}$", i).unwrap();
+                                compute_field_path(cx, name, field, inner_offset, size);
+                            }
                         }
                     }
+                    compute_field_path(cx, &mut name,
+                                       self.layout,
+                                       self.layout.fields.offset(0),
+                                       self.layout.field(cx, 0).size);
+                    name.push_str(&adt.variants[*niche_variants.start()].name.as_str());
+
+                    // Create the (singleton) list of descriptions of union members.
+                    vec![
+                        MemberDescription {
+                            name,
+                            type_metadata: variant_type_metadata,
+                            offset: Size::ZERO,
+                            size: variant.size,
+                            align: variant.align,
+                            flags: DIFlags::FlagZero,
+                            discriminant: None,
+                        }
+                    ]
+                } else {
+                    (0..variants.len()).map(|i| {
+                        let variant = self.layout.for_variant(cx, i);
+                        let (variant_type_metadata, member_desc_factory) =
+                            describe_enum_variant(cx,
+                                                  variant,
+                                                  &adt.variants[i],
+                                                  OptimizedDiscriminant,
+                                                  self_metadata,
+                                                  self.span);
+
+                        let member_descriptions = member_desc_factory
+                            .create_member_descriptions(cx);
+
+                        set_members_of_composite_type(cx,
+                                                      variant_type_metadata,
+                                                      member_descriptions);
+
+                        let niche_value = if i == dataful_variant {
+                            None
+                        } else {
+                            let niche = (i as u128)
+                                .wrapping_sub(*niche_variants.start() as u128)
+                                .wrapping_add(niche_start);
+                            assert_eq!(niche as u64 as u128, niche);
+                            Some(niche as u64)
+                        };
+
+                        MemberDescription {
+                            name: adt.variants[i].name.as_str().to_string(),
+                            type_metadata: variant_type_metadata,
+                            offset: Size::ZERO,
+                            size: self.layout.size,
+                            align: self.layout.align,
+                            flags: DIFlags::FlagZero,
+                            discriminant: niche_value,
+                        }
+                    }).collect()
                 }
-                compute_field_path(cx, &mut name,
-                                   self.layout,
-                                   self.layout.fields.offset(0),
-                                   self.layout.field(cx, 0).size);
-                name.push_str(&adt.variants[*niche_variants.start()].name.as_str());
-
-                // Create the (singleton) list of descriptions of union members.
-                vec![
-                    MemberDescription {
-                        name,
-                        type_metadata: variant_type_metadata,
-                        offset: Size::ZERO,
-                        size: variant.size,
-                        align: variant.align,
-                        flags: DIFlags::FlagZero
-                    }
-                ]
             }
         }
     }
@@ -1297,14 +1400,19 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
             let (size, align) = cx.size_and_align_of(ty);
             MemberDescription {
                 name: name.to_string(),
-                type_metadata: match self.discriminant_type_metadata {
-                    Some(metadata) if i == 0 => metadata,
-                    _ => type_metadata(cx, ty, self.span)
+                type_metadata: if use_enum_fallback(cx) {
+                    match self.discriminant_type_metadata {
+                        Some(metadata) if i == 0 => metadata,
+                        _ => type_metadata(cx, ty, self.span)
+                    }
+                } else {
+                    type_metadata(cx, ty, self.span)
                 },
                 offset: self.offsets[i],
                 size,
                 align,
-                flags: DIFlags::FlagZero
+                flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1317,10 +1425,10 @@ enum EnumDiscriminantInfo<'ll> {
     NoDiscriminant
 }
 
-// Returns a tuple of (1) type_metadata_stub of the variant, (2) the llvm_type
-// of the variant, and (3) a MemberDescriptionFactory for producing the
-// descriptions of the fields of the variant. This is a rudimentary version of a
-// full RecursiveTypeDescription.
+// Returns a tuple of (1) type_metadata_stub of the variant, (2) a
+// MemberDescriptionFactory for producing the descriptions of the
+// fields of the variant. This is a rudimentary version of a full
+// RecursiveTypeDescription.
 fn describe_enum_variant(
     cx: &CodegenCx<'ll, 'tcx>,
     layout: layout::TyLayout<'tcx>,
@@ -1343,29 +1451,46 @@ fn describe_enum_variant(
                                            unique_type_id,
                                            Some(containing_scope));
 
-    // If this is not a univariant enum, there is also the discriminant field.
-    let (discr_offset, discr_arg) = match discriminant_info {
-        RegularDiscriminant(_) => {
-            // We have the layout of an enum variant, we need the layout of the outer enum
-            let enum_layout = cx.layout_of(layout.ty);
-            (Some(enum_layout.fields.offset(0)),
-             Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
-        }
-        _ => (None, None),
-    };
-    let offsets = discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| {
-        layout.fields.offset(i)
-    })).collect();
-
     // Build an array of (field name, field type) pairs to be captured in the factory closure.
-    let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
-        let name = if variant.ctor_kind == CtorKind::Fn {
-            format!("__{}", i)
-        } else {
-            variant.fields[i].ident.to_string()
+    let (offsets, args) = if use_enum_fallback(cx) {
+        // If this is not a univariant enum, there is also the discriminant field.
+        let (discr_offset, discr_arg) = match discriminant_info {
+            RegularDiscriminant(_) => {
+                // We have the layout of an enum variant, we need the layout of the outer enum
+                let enum_layout = cx.layout_of(layout.ty);
+                (Some(enum_layout.fields.offset(0)),
+                 Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
+            }
+            _ => (None, None),
         };
-        (name, layout.field(cx, i).ty)
-    })).collect();
+        (
+            discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| {
+                layout.fields.offset(i)
+            })).collect(),
+            discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
+                let name = if variant.ctor_kind == CtorKind::Fn {
+                    format!("__{}", i)
+                } else {
+                    variant.fields[i].ident.to_string()
+                };
+                (name, layout.field(cx, i).ty)
+            })).collect()
+        )
+    } else {
+        (
+            (0..layout.fields.count()).map(|i| {
+                layout.fields.offset(i)
+            }).collect(),
+            (0..layout.fields.count()).map(|i| {
+                let name = if variant.ctor_kind == CtorKind::Fn {
+                    format!("__{}", i)
+                } else {
+                    variant.fields[i].ident.to_string()
+                };
+                (name, layout.field(cx, i).ty)
+            }).collect()
+        )
+    };
 
     let member_description_factory =
         VariantMDF(VariantMemberDescriptionFactory {
@@ -1401,22 +1526,22 @@ fn prepare_enum_metadata(
     // <unknown>
     let file_metadata = unknown_file_metadata(cx);
 
-    let def = enum_type.ty_adt_def().unwrap();
-    let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
-        .zip(&def.variants)
-        .map(|(discr, v)| {
-            let name = SmallCStr::new(&v.name.as_str());
-            unsafe {
-                Some(llvm::LLVMRustDIBuilderCreateEnumerator(
-                    DIB(cx),
-                    name.as_ptr(),
-                    // FIXME: what if enumeration has i128 discriminant?
-                    discr.val as u64))
-            }
-        })
-        .collect();
-
     let discriminant_type_metadata = |discr: layout::Primitive| {
+        let def = enum_type.ty_adt_def().unwrap();
+        let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
+            .zip(&def.variants)
+            .map(|(discr, v)| {
+                let name = SmallCStr::new(&v.name.as_str());
+                unsafe {
+                    Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+                        DIB(cx),
+                        name.as_ptr(),
+                        // FIXME: what if enumeration has i128 discriminant?
+                        discr.val as u64))
+                }
+            })
+            .collect();
+
         let disr_type_key = (enum_def_id, discr);
         let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
                                                                  .borrow()
@@ -1441,7 +1566,7 @@ fn prepare_enum_metadata(
                         discriminant_size.bits(),
                         discriminant_align.abi_bits() as u32,
                         create_DIArray(DIB(cx), &enumerators_metadata),
-                        discriminant_base_type_metadata)
+                        discriminant_base_type_metadata, true)
                 };
 
                 debug_context(cx).created_enum_disr_types
@@ -1455,16 +1580,10 @@ fn prepare_enum_metadata(
 
     let layout = cx.layout_of(enum_type);
 
-    let discriminant_type_metadata = match layout.variants {
-        layout::Variants::Single { .. } |
-        layout::Variants::NicheFilling { .. } => None,
-        layout::Variants::Tagged { ref tag, .. } => {
-            Some(discriminant_type_metadata(tag.value))
-        }
-    };
-
-    if let (&layout::Abi::Scalar(_), Some(discr)) = (&layout.abi, discriminant_type_metadata) {
-        return FinalMetadata(discr);
+    match (&layout.abi, &layout.variants) {
+        (&layout::Abi::Scalar(_), &layout::Variants::Tagged {ref tag, .. }) =>
+            return FinalMetadata(discriminant_type_metadata(tag.value)),
+        _ => {}
     }
 
     let (enum_type_size, enum_type_align) = layout.size_and_align();
@@ -1473,30 +1592,145 @@ fn prepare_enum_metadata(
     let unique_type_id_str = SmallCStr::new(
         debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
     );
-    let enum_metadata = unsafe {
-        llvm::LLVMRustDIBuilderCreateUnionType(
-        DIB(cx),
-        containing_scope,
-        enum_name.as_ptr(),
-        file_metadata,
-        UNKNOWN_LINE_NUMBER,
-        enum_type_size.bits(),
-        enum_type_align.abi_bits() as u32,
-        DIFlags::FlagZero,
-        None,
-        0, // RuntimeLang
-        unique_type_id_str.as_ptr())
+
+    if use_enum_fallback(cx) {
+        let discriminant_type_metadata = match layout.variants {
+            layout::Variants::Single { .. } |
+            layout::Variants::NicheFilling { .. } => None,
+            layout::Variants::Tagged { ref tag, .. } => {
+                Some(discriminant_type_metadata(tag.value))
+            }
+        };
+
+        let enum_metadata = unsafe {
+            llvm::LLVMRustDIBuilderCreateUnionType(
+                DIB(cx),
+                containing_scope,
+                enum_name.as_ptr(),
+                file_metadata,
+                UNKNOWN_LINE_NUMBER,
+                enum_type_size.bits(),
+                enum_type_align.abi_bits() as u32,
+                DIFlags::FlagZero,
+                None,
+                0, // RuntimeLang
+                unique_type_id_str.as_ptr())
+        };
+
+        return create_and_register_recursive_type_forward_declaration(
+            cx,
+            enum_type,
+            unique_type_id,
+            enum_metadata,
+            enum_metadata,
+            EnumMDF(EnumMemberDescriptionFactory {
+                enum_type,
+                layout,
+                discriminant_type_metadata,
+                containing_scope,
+                span,
+            }),
+        );
+    }
+
+    let discriminator_metadata = match &layout.variants {
+        // A single-variant enum has no discriminant.
+        &layout::Variants::Single { .. } => None,
+
+        &layout::Variants::NicheFilling { ref niche, .. } => {
+            // Find the integer type of the correct size.
+            let size = niche.value.size(cx);
+            let align = niche.value.align(cx);
+
+            let discr_type = match niche.value {
+                layout::Int(t, _) => t,
+                layout::Float(layout::FloatTy::F32) => Integer::I32,
+                layout::Float(layout::FloatTy::F64) => Integer::I64,
+                layout::Pointer => cx.data_layout().ptr_sized_integer(),
+            }.to_ty(cx.tcx, false);
+
+            let discr_metadata = basic_type_metadata(cx, discr_type);
+            unsafe {
+                Some(llvm::LLVMRustDIBuilderCreateMemberType(
+                    DIB(cx),
+                    containing_scope,
+                    ptr::null_mut(),
+                    file_metadata,
+                    UNKNOWN_LINE_NUMBER,
+                    size.bits(),
+                    align.abi_bits() as u32,
+                    layout.fields.offset(0).bits(),
+                    DIFlags::FlagArtificial,
+                    discr_metadata))
+            }
+        },
+
+        &layout::Variants::Tagged { ref tag, .. } => {
+            let discr_type = tag.value.to_ty(cx.tcx);
+            let (size, align) = cx.size_and_align_of(discr_type);
+
+            let discr_metadata = basic_type_metadata(cx, discr_type);
+            unsafe {
+                Some(llvm::LLVMRustDIBuilderCreateMemberType(
+                    DIB(cx),
+                    containing_scope,
+                    ptr::null_mut(),
+                    file_metadata,
+                    UNKNOWN_LINE_NUMBER,
+                    size.bits(),
+                    align.abi_bits() as u32,
+                    layout.fields.offset(0).bits(),
+                    DIFlags::FlagArtificial,
+                    discr_metadata))
+            }
+        },
+    };
+
+    let empty_array = create_DIArray(DIB(cx), &[]);
+    let variant_part = unsafe {
+        llvm::LLVMRustDIBuilderCreateVariantPart(
+            DIB(cx),
+            containing_scope,
+            ptr::null_mut(),
+            file_metadata,
+            UNKNOWN_LINE_NUMBER,
+            enum_type_size.bits(),
+            enum_type_align.abi_bits() as u32,
+            DIFlags::FlagZero,
+            discriminator_metadata,
+            empty_array,
+            unique_type_id_str.as_ptr())
+    };
+
+    // The variant part must be wrapped in a struct according to DWARF.
+    let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
+    let struct_wrapper = unsafe {
+        llvm::LLVMRustDIBuilderCreateStructType(
+            DIB(cx),
+            Some(containing_scope),
+            enum_name.as_ptr(),
+            file_metadata,
+            UNKNOWN_LINE_NUMBER,
+            enum_type_size.bits(),
+            enum_type_align.abi_bits() as u32,
+            DIFlags::FlagZero,
+            None,
+            type_array,
+            0,
+            None,
+            unique_type_id_str.as_ptr())
     };
 
     return create_and_register_recursive_type_forward_declaration(
         cx,
         enum_type,
         unique_type_id,
-        enum_metadata,
+        struct_wrapper,
+        variant_part,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type,
             layout,
-            discriminant_type_metadata,
+            discriminant_type_metadata: None,
             containing_scope,
             span,
         }),
@@ -1565,7 +1799,7 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
         .map(|member_description| {
             let member_name = CString::new(member_description.name).unwrap();
             unsafe {
-                Some(llvm::LLVMRustDIBuilderCreateMemberType(
+                Some(llvm::LLVMRustDIBuilderCreateVariantMemberType(
                     DIB(cx),
                     composite_type_metadata,
                     member_name.as_ptr(),
@@ -1574,6 +1808,10 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
                     member_description.size.bits(),
                     member_description.align.abi_bits() as u32,
                     member_description.offset.bits(),
+                    match member_description.discriminant {
+                        None => None,
+                        Some(value) => Some(C_u64(cx, value)),
+                    },
                     member_description.flags,
                     member_description.type_metadata))
             }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 0b98fa4eaf5..f046ea03027 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1307,6 +1307,19 @@ extern "C" {
                                              Ty: &'a DIType)
                                              -> &'a DIDerivedType;
 
+    pub fn LLVMRustDIBuilderCreateVariantMemberType(Builder: &DIBuilder<'a>,
+                                                    Scope: &'a DIScope,
+                                                    Name: *const c_char,
+                                                    File: &'a DIFile,
+                                                    LineNumber: c_uint,
+                                                    SizeInBits: u64,
+                                                    AlignInBits: u32,
+                                                    OffsetInBits: u64,
+                                                    Discriminant: Option<&'a Value>,
+                                                    Flags: DIFlags,
+                                                    Ty: &'a DIType)
+                                                    -> &'a DIType;
+
     pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: &DIBuilder<'a>,
                                                Scope: &'a DIScope,
                                                File: &'a DIFile,
@@ -1384,7 +1397,8 @@ extern "C" {
                                                   SizeInBits: u64,
                                                   AlignInBits: u32,
                                                   Elements: &'a DIArray,
-                                                  ClassType: &'a DIType)
+                                                  ClassType: &'a DIType,
+                                                  IsFixed: bool)
                                                   -> &'a DIType;
 
     pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>,
@@ -1400,6 +1414,19 @@ extern "C" {
                                             UniqueId: *const c_char)
                                             -> &'a DIType;
 
+    pub fn LLVMRustDIBuilderCreateVariantPart(Builder: &DIBuilder<'a>,
+                                              Scope: &'a DIScope,
+                                              Name: *const c_char,
+                                              File: &'a DIFile,
+                                              LineNo: c_uint,
+                                              SizeInBits: u64,
+                                              AlignInBits: u32,
+                                              Flags: DIFlags,
+                                              Discriminator: Option<&'a DIDerivedType>,
+                                              Elements: &'a DIArray,
+                                              UniqueId: *const c_char)
+                                              -> &'a DIDerivedType;
+
     pub fn LLVMSetUnnamedAddr(GlobalVar: &Value, UnnamedAddr: Bool);
 
     pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: &DIBuilder<'a>,
diff --git a/src/llvm b/src/llvm
-Subproject caddcd9b9dc9479a20908d93c3e47c49b021379
+Subproject 7051ead40a5f825878b59bf08d4e768be9e99a4
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index bf7afa1b6c0..affec73e3ac 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -713,6 +713,21 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
       unwrapDI<DIType>(VTableHolder), UniqueId));
 }
 
+extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
+    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
+    uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator,
+    LLVMMetadataRef Elements, const char *UniqueId) {
+#if LLVM_VERSION_GE(7, 0)
+  return wrap(Builder->createVariantPart(
+      unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
+      SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator),
+      DINodeArray(unwrapDI<MDTuple>(Elements)), UniqueId));
+#else
+  abort();
+#endif
+}
+
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
@@ -724,6 +739,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
                                         fromRust(Flags), unwrapDI<DIType>(Ty)));
 }
 
+extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
+    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
+    const char *Name, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
+    uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant,
+    LLVMRustDIFlags Flags, LLVMMetadataRef Ty) {
+#if LLVM_VERSION_GE(7, 0)
+  llvm::ConstantInt* D = nullptr;
+  if (Discriminant) {
+    D = unwrap<llvm::ConstantInt>(Discriminant);
+  }
+  return wrap(Builder->createVariantMemberType(unwrapDI<DIDescriptor>(Scope), Name,
+                                               unwrapDI<DIFile>(File), LineNo,
+                                               SizeInBits, AlignInBits, OffsetInBits, D,
+                                               fromRust(Flags), unwrapDI<DIType>(Ty)));
+#else
+  return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), Name,
+                                        unwrapDI<DIFile>(File), LineNo,
+                                        SizeInBits, AlignInBits, OffsetInBits,
+                                        fromRust(Flags), unwrapDI<DIType>(Ty)));
+#endif
+}
+
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
     LLVMMetadataRef File, unsigned Line, unsigned Col) {
@@ -826,11 +863,19 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
     uint32_t AlignInBits, LLVMMetadataRef Elements,
-    LLVMMetadataRef ClassTy) {
+    LLVMMetadataRef ClassTy, bool IsFixed) {
+#if LLVM_VERSION_GE(7, 0)
   return wrap(Builder->createEnumerationType(
       unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
       SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
-      unwrapDI<DIType>(ClassTy)));
+      unwrapDI<DIType>(ClassTy), "", IsFixed));
+#else
+  // Ignore IsFixed on older LLVM.
+  return wrap(Builder->createEnumerationType(
+      unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
+      SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
+      unwrapDI<DIType>(ClassTy), ""));
+#endif
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
diff --git a/src/test/codegen/enum-debug-clike.rs b/src/test/codegen/enum-debug-clike.rs
new file mode 100644
index 00000000000..528e84b298c
--- /dev/null
+++ b/src/test/codegen/enum-debug-clike.rs
@@ -0,0 +1,35 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test depends on a patch that was committed to upstream LLVM
+// before 7.0, then backported to the Rust LLVM fork.  It tests that
+// debug info for "c-like" enums is properly emitted.
+
+// ignore-tidy-linelength
+// ignore-windows
+// min-system-llvm-version 7.0
+
+// compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "E",{{.*}}flags: DIFlagFixedEnum,{{.*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "A",{{.*}}value: {{[0-9].*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "B",{{.*}}value: {{[0-9].*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "C",{{.*}}value: {{[0-9].*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+enum E { A, B, C }
+
+pub fn main() {
+    let e = E::C;
+}
diff --git a/src/test/codegen/enum-debug-niche.rs b/src/test/codegen/enum-debug-niche.rs
new file mode 100644
index 00000000000..6326ba93266
--- /dev/null
+++ b/src/test/codegen/enum-debug-niche.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test depends on a patch that was committed to upstream LLVM
+// before 7.0, then backported to the Rust LLVM fork.  It tests that
+// optimized enum debug info accurately reflects the enum layout.
+
+// ignore-tidy-linelength
+// ignore-windows
+// min-system-llvm-version 7.0
+
+// compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "C",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "C",{{.*}}
+// CHECK-NOT: {{.*}}DIDerivedType{{.*}}name: "D",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "D",{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "D",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+enum E { A, B, C, D(bool) }
+
+pub fn main() {
+    let e = E::D(true);
+}
diff --git a/src/test/codegen/enum-debug-tagged.rs b/src/test/codegen/enum-debug-tagged.rs
new file mode 100644
index 00000000000..e862d29c940
--- /dev/null
+++ b/src/test/codegen/enum-debug-tagged.rs
@@ -0,0 +1,40 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test depends on a patch that was committed to upstream LLVM
+// before 7.0, then backported to the Rust LLVM fork.  It tests that
+// debug info for tagged (ordinary) enums is properly emitted.
+
+// ignore-tidy-linelength
+// ignore-windows
+// min-system-llvm-version 7.0
+
+// compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "E",{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+enum E { A(u32), B(u32) }
+
+pub fn main() {
+    let e = E::A(23);
+}
diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs
index 75737cd6f13..dcd4588af76 100644
--- a/src/test/debuginfo/basic-types.rs
+++ b/src/test/debuginfo/basic-types.rs
@@ -16,6 +16,10 @@
 
 // min-lldb-version: 310
 
+// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
+// for now.
+// only-macos
+
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
diff --git a/src/test/debuginfo/borrowed-enum-legacy.rs b/src/test/debuginfo/borrowed-enum-legacy.rs
new file mode 100644
index 00000000000..a04f7d6dd8a
--- /dev/null
+++ b/src/test/debuginfo/borrowed-enum-legacy.rs
@@ -0,0 +1,94 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// min-lldb-version: 310
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 7.11.90 - 7.12.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+
+// gdb-command:print *the_a_ref
+// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
+// gdbr-check:$1 = borrowed_enum_legacy::ABC::TheA{x: 0, y: 8970181431921507452}
+
+// gdb-command:print *the_b_ref
+// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
+// gdbr-check:$2 = borrowed_enum_legacy::ABC::TheB(0, 286331153, 286331153)
+
+// gdb-command:print *univariant_ref
+// gdbg-check:$3 = {{__0 = 4820353753753434}}
+// gdbr-check:$3 = borrowed_enum_legacy::Univariant::TheOnlyCase(4820353753753434)
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+
+// lldb-command:print *the_a_ref
+// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbr-check:(borrowed_enum_legacy::ABC::TheA) *the_a_ref = TheA { borrowed_enum_legacy::ABC::TheA: 0, borrowed_enum_legacy::ABC::TheB: 8970181431921507452 }
+// lldb-command:print *the_b_ref
+// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbr-check:(borrowed_enum_legacy::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
+// lldb-command:print *univariant_ref
+// lldbg-check:[...]$2 = TheOnlyCase(4820353753753434)
+// lldbr-check:(borrowed_enum_legacy::Univariant) *univariant_ref = { borrowed_enum_legacy::TheOnlyCase = { = 4820353753753434 } }
+
+#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum ABC {
+    TheA { x: i64, y: i64 },
+    TheB (i64, i32, i32),
+}
+
+// This is a special case since it does not have the implicit discriminant field.
+enum Univariant {
+    TheOnlyCase(i64)
+}
+
+fn main() {
+
+    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+    // 0b01111100011111000111110001111100 = 2088533116
+    // 0b0111110001111100 = 31868
+    // 0b01111100 = 124
+    let the_a = ABC::TheA { x: 0, y: 8970181431921507452 };
+    let the_a_ref: &ABC = &the_a;
+
+    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+    // 0b00010001000100010001000100010001 = 286331153
+    // 0b0001000100010001 = 4369
+    // 0b00010001 = 17
+    let the_b = ABC::TheB (0, 286331153, 286331153);
+    let the_b_ref: &ABC = &the_b;
+
+    let univariant = Univariant::TheOnlyCase(4820353753753434);
+    let univariant_ref: &Univariant = &univariant;
+
+    zzz(); // #break
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs
index 9143e83343f..8362934166c 100644
--- a/src/test/debuginfo/borrowed-enum.rs
+++ b/src/test/debuginfo/borrowed-enum.rs
@@ -9,8 +9,11 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb or lldb that can read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
+// rust-lldb
 
 // compile-flags:-g
 
@@ -19,15 +22,12 @@
 // gdb-command:run
 
 // gdb-command:print *the_a_ref
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
 // gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452}
 
 // gdb-command:print *the_b_ref
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
 // gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153)
 
 // gdb-command:print *univariant_ref
-// gdbg-check:$3 = {{__0 = 4820353753753434}}
 // gdbr-check:$3 = borrowed_enum::Univariant::TheOnlyCase(4820353753753434)
 
 
@@ -36,14 +36,11 @@
 // lldb-command:run
 
 // lldb-command:print *the_a_ref
-// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
-// lldbr-check:(borrowed_enum::ABC::TheA) *the_a_ref = TheA { borrowed_enum::ABC::TheA: 0, borrowed_enum::ABC::TheB: 8970181431921507452 }
+// lldbr-check:(borrowed_enum::ABC::TheA) *the_a_ref = TheA { TheA: 0, TheB: 8970181431921507452 }
 // lldb-command:print *the_b_ref
-// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
 // lldbr-check:(borrowed_enum::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
 // lldb-command:print *univariant_ref
-// lldbg-check:[...]$2 = TheOnlyCase(4820353753753434)
-// lldbr-check:(borrowed_enum::Univariant) *univariant_ref = { borrowed_enum::TheOnlyCase = { = 4820353753753434 } }
+// lldbr-check:(borrowed_enum::Univariant) *univariant_ref = { TheOnlyCase = { = 4820353753753434 } }
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/cross-crate-spans.rs b/src/test/debuginfo/cross-crate-spans.rs
index 9002e19ce21..715024a2ef9 100644
--- a/src/test/debuginfo/cross-crate-spans.rs
+++ b/src/test/debuginfo/cross-crate-spans.rs
@@ -13,6 +13,10 @@
 
 // min-lldb-version: 310
 
+// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
+// for now.
+// only-macos
+
 // aux-build:cross_crate_spans.rs
 extern crate cross_crate_spans;
 
diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs
index 48231a906c9..77583ab1037 100644
--- a/src/test/debuginfo/destructured-for-loop-variable.rs
+++ b/src/test/debuginfo/destructured-for-loop-variable.rs
@@ -12,6 +12,10 @@
 
 // min-lldb-version: 310
 
+// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
+// for now.
+// only-macos
+
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
diff --git a/src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs b/src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs
new file mode 100644
index 00000000000..092b31b7c30
--- /dev/null
+++ b/src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs
@@ -0,0 +1,115 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// ignore-lldb: FIXME(#27089)
+// min-lldb-version: 310
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+
+// gdb-command:print eight_bytes1
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}}
+// gdbr-check:$1 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(100)
+
+// gdb-command:print four_bytes1
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}}
+// gdbr-check:$2 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(101)
+
+// gdb-command:print two_bytes1
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}}
+// gdbr-check:$3 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(102)
+
+// gdb-command:print one_byte1
+// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}}
+// gdbr-check:$4 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(65)
+
+
+// gdb-command:print eight_bytes2
+// gdbg-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}}
+// gdbr-check:$5 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(100)
+
+// gdb-command:print four_bytes2
+// gdbg-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}}
+// gdbr-check:$6 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(101)
+
+// gdb-command:print two_bytes2
+// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}}
+// gdbr-check:$7 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(102)
+
+// gdb-command:print one_byte2
+// gdbg-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}}
+// gdbr-check:$8 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(65)
+
+// gdb-command:continue
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+
+// lldb-command:print eight_bytes1
+// lldb-check:[...]$0 = Variant1(100)
+// lldb-command:print four_bytes1
+// lldb-check:[...]$1 = Variant1(101)
+// lldb-command:print two_bytes1
+// lldb-check:[...]$2 = Variant1(102)
+// lldb-command:print one_byte1
+// lldb-check:[...]$3 = Variant1('A')
+
+// lldb-command:print eight_bytes2
+// lldb-check:[...]$4 = Variant2(100)
+// lldb-command:print four_bytes2
+// lldb-check:[...]$5 = Variant2(101)
+// lldb-command:print two_bytes2
+// lldb-check:[...]$6 = Variant2(102)
+// lldb-command:print one_byte2
+// lldb-check:[...]$7 = Variant2('A')
+
+// lldb-command:continue
+
+#![allow(unused_variables)]
+#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+// This test case makes sure that we get correct type descriptions for the enum
+// discriminant of different instantiations of the same generic enum type where,
+// dependending on the generic type parameter(s), the discriminant has a
+// different size in memory.
+
+enum Enum<T> {
+    Variant1(T),
+    Variant2(T)
+}
+
+fn main() {
+    // These are ordered for descending size on purpose
+    let eight_bytes1 = Enum::Variant1(100.0f64);
+    let four_bytes1 = Enum::Variant1(101i32);
+    let two_bytes1 = Enum::Variant1(102i16);
+    let one_byte1 = Enum::Variant1(65u8);
+
+    let eight_bytes2 = Enum::Variant2(100.0f64);
+    let four_bytes2 = Enum::Variant2(101i32);
+    let two_bytes2 = Enum::Variant2(102i16);
+    let one_byte2 = Enum::Variant2(65u8);
+
+    zzz(); // #break
+}
+
+fn zzz() { () }
diff --git a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs
index 1fc05b3752f..988ec4a65f1 100644
--- a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs
+++ b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs
@@ -12,43 +12,39 @@
 // ignore-lldb: FIXME(#27089)
 // min-lldb-version: 310
 
+// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
+
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
 // gdb-command:run
 
 // gdb-command:print eight_bytes1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}}
-// gdbr-check:$1 = generic_enum_with_different_disr_sizes::Enum::Variant1(100)
+// gdbr-check:$1 = generic_enum_with_different_disr_sizes::Enum<f64>::Variant1(100)
 
 // gdb-command:print four_bytes1
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}}
-// gdbr-check:$2 = generic_enum_with_different_disr_sizes::Enum::Variant1(101)
+// gdbr-check:$2 = generic_enum_with_different_disr_sizes::Enum<i32>::Variant1(101)
 
 // gdb-command:print two_bytes1
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}}
-// gdbr-check:$3 = generic_enum_with_different_disr_sizes::Enum::Variant1(102)
+// gdbr-check:$3 = generic_enum_with_different_disr_sizes::Enum<i16>::Variant1(102)
 
 // gdb-command:print one_byte1
-// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}}
-// gdbr-check:$4 = generic_enum_with_different_disr_sizes::Enum::Variant1(65)
+// gdbr-check:$4 = generic_enum_with_different_disr_sizes::Enum<u8>::Variant1(65)
 
 
 // gdb-command:print eight_bytes2
-// gdbg-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}}
-// gdbr-check:$5 = generic_enum_with_different_disr_sizes::Enum::Variant2(100)
+// gdbr-check:$5 = generic_enum_with_different_disr_sizes::Enum<f64>::Variant2(100)
 
 // gdb-command:print four_bytes2
-// gdbg-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}}
-// gdbr-check:$6 = generic_enum_with_different_disr_sizes::Enum::Variant2(101)
+// gdbr-check:$6 = generic_enum_with_different_disr_sizes::Enum<i32>::Variant2(101)
 
 // gdb-command:print two_bytes2
-// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}}
-// gdbr-check:$7 = generic_enum_with_different_disr_sizes::Enum::Variant2(102)
+// gdbr-check:$7 = generic_enum_with_different_disr_sizes::Enum<i16>::Variant2(102)
 
 // gdb-command:print one_byte2
-// gdbg-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}}
-// gdbr-check:$8 = generic_enum_with_different_disr_sizes::Enum::Variant2(65)
+// gdbr-check:$8 = generic_enum_with_different_disr_sizes::Enum<u8>::Variant2(65)
 
 // gdb-command:continue
 
diff --git a/src/test/debuginfo/generic-struct-style-enum-legacy.rs b/src/test/debuginfo/generic-struct-style-enum-legacy.rs
new file mode 100644
index 00000000000..47c4ea77e44
--- /dev/null
+++ b/src/test/debuginfo/generic-struct-style-enum-legacy.rs
@@ -0,0 +1,96 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// min-lldb-version: 310
+// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// gdb-command:set print union on
+// gdb-command:run
+
+// gdb-command:print case1
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
+// gdbr-check:$1 = generic_struct_style_enum_legacy::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
+
+// gdb-command:print case2
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
+// gdbr-check:$2 = generic_struct_style_enum_legacy::Regular::Case2{a: 0, b: 286331153, c: 286331153}
+
+// gdb-command:print case3
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
+// gdbr-check:$3 = generic_struct_style_enum_legacy::Regular::Case3{a: 0, b: 6438275382588823897}
+
+// gdb-command:print univariant
+// gdbg-check:$4 = {{a = -1}}
+// gdbr-check:$4 = generic_struct_style_enum_legacy::Univariant<i32>::TheOnlyCase{a: -1}
+
+
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+use self::Regular::{Case1, Case2, Case3};
+use self::Univariant::TheOnlyCase;
+
+// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
+// substituted with something of size `xx` bits and the same alignment as an integer type of the
+// same size.
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular<T16, T32, T64> {
+    Case1 { a: T64, b: T16, c: T16, d: T16, e: T16},
+    Case2 { a: T64, b: T32, c: T32},
+    Case3 { a: T64, b: T64 }
+}
+
+enum Univariant<T> {
+    TheOnlyCase { a: T }
+}
+
+fn main() {
+
+    // In order to avoid endianness trouble all of the following test values consist of a single
+    // repeated byte. This way each interpretation of the union should look the same, no matter if
+    // this is a big or little endian machine.
+
+    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+    // 0b01111100011111000111110001111100 = 2088533116
+    // 0b0111110001111100 = 31868
+    // 0b01111100 = 124
+    let case1: Regular<u16, u32, i64> = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
+
+    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+    // 0b00010001000100010001000100010001 = 286331153
+    // 0b0001000100010001 = 4369
+    // 0b00010001 = 17
+    let case2: Regular<i16, u32, i64>  = Case2 { a: 0, b: 286331153, c: 286331153 };
+
+    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+    // 0b01011001010110010101100101011001 = 1499027801
+    // 0b0101100101011001 = 22873
+    // 0b01011001 = 89
+    let case3: Regular<u16, i32, u64>  = Case3 { a: 0, b: 6438275382588823897 };
+
+    let univariant = TheOnlyCase { a: -1 };
+
+    zzz(); // #break
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/generic-struct-style-enum.rs b/src/test/debuginfo/generic-struct-style-enum.rs
index 4a1d14ccf61..e08cde03c47 100644
--- a/src/test/debuginfo/generic-struct-style-enum.rs
+++ b/src/test/debuginfo/generic-struct-style-enum.rs
@@ -10,7 +10,10 @@
 
 // ignore-tidy-linelength
 // min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
 
 // compile-flags:-g
 
@@ -18,19 +21,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
-// gdbr-check:$1 = generic_struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
+// gdbr-check:$1 = generic_struct_style_enum::Regular<u16, u32, i64>::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
-// gdbr-check:$2 = generic_struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
+// gdbr-check:$2 = generic_struct_style_enum::Regular<i16, u32, i64>::Case2{a: 0, b: 286331153, c: 286331153}
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
-// gdbr-check:$3 = generic_struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
+// gdbr-check:$3 = generic_struct_style_enum::Regular<u16, i32, u64>::Case3{a: 0, b: 6438275382588823897}
 
 // gdb-command:print univariant
-// gdbg-check:$4 = {{a = -1}}
 // gdbr-check:$4 = generic_struct_style_enum::Univariant<i32>::TheOnlyCase{a: -1}
 
 
diff --git a/src/test/debuginfo/generic-tuple-style-enum-legacy.rs b/src/test/debuginfo/generic-tuple-style-enum-legacy.rs
new file mode 100644
index 00000000000..ee28968619d
--- /dev/null
+++ b/src/test/debuginfo/generic-tuple-style-enum-legacy.rs
@@ -0,0 +1,118 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// min-lldb-version: 310
+// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:set print union on
+// gdb-command:run
+
+// gdb-command:print case1
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
+// gdbr-check:$1 = generic_tuple_style_enum_legacy::Regular::Case1(0, 31868, 31868, 31868, 31868)
+
+// gdb-command:print case2
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
+// gdbr-check:$2 = generic_tuple_style_enum_legacy::Regular::Case2(0, 286331153, 286331153)
+
+// gdb-command:print case3
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
+// gdbr-check:$3 = generic_tuple_style_enum_legacy::Regular::Case3(0, 6438275382588823897)
+
+// gdb-command:print univariant
+// gdbg-check:$4 = {{__0 = -1}}
+// gdbr-check:$4 = generic_tuple_style_enum_legacy::Univariant<i64>::TheOnlyCase(-1)
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+
+// lldb-command:print case1
+// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbr-check:(generic_tuple_style_enum_legacy::Regular<u16, u32, u64>::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
+
+// lldb-command:print case2
+// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbr-check:(generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case2) case2 = Regular<i16, i32, i64>::Case2 { generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case2: 286331153, generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case3: 286331153 }
+
+// lldb-command:print case3
+// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbr-check:(generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case3) case3 = Regular<i16, i32, i64>::Case3 { generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case2: 6438275382588823897 }
+
+// lldb-command:print univariant
+// lldbg-check:[...]$3 = TheOnlyCase(-1)
+// lldbr-check:(generic_tuple_style_enum_legacy::Univariant<i64>) univariant = { generic_tuple_style_enum_legacy::TheOnlyCase = { = -1 } }
+
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+use self::Regular::{Case1, Case2, Case3};
+use self::Univariant::TheOnlyCase;
+
+// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
+// substituted with something of size `xx` bits and the same alignment as an integer type of the
+// same size.
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular<T16, T32, T64> {
+    Case1(T64, T16, T16, T16, T16),
+    Case2(T64, T32, T32),
+    Case3(T64, T64)
+}
+
+enum Univariant<T64> {
+    TheOnlyCase(T64)
+}
+
+fn main() {
+
+    // In order to avoid endianness trouble all of the following test values consist of a single
+    // repeated byte. This way each interpretation of the union should look the same, no matter if
+    // this is a big or little endian machine.
+
+    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+    // 0b01111100011111000111110001111100 = 2088533116
+    // 0b0111110001111100 = 31868
+    // 0b01111100 = 124
+    let case1: Regular<u16, u32, u64> = Case1(0_u64, 31868_u16, 31868_u16, 31868_u16, 31868_u16);
+
+    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+    // 0b00010001000100010001000100010001 = 286331153
+    // 0b0001000100010001 = 4369
+    // 0b00010001 = 17
+    let case2: Regular<i16, i32, i64> = Case2(0_i64, 286331153_i32, 286331153_i32);
+
+    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+    // 0b01011001010110010101100101011001 = 1499027801
+    // 0b0101100101011001 = 22873
+    // 0b01011001 = 89
+    let case3: Regular<i16, i32, i64> = Case3(0_i64, 6438275382588823897_i64);
+
+    let univariant = TheOnlyCase(-1_i64);
+
+    zzz(); // #break
+}
+
+fn zzz() { () }
diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs
index 62bec28a022..ebd43daf464 100644
--- a/src/test/debuginfo/generic-tuple-style-enum.rs
+++ b/src/test/debuginfo/generic-tuple-style-enum.rs
@@ -9,8 +9,12 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb and lldb that can
+// read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
+// rust-lldb
 
 // compile-flags:-g
 
@@ -20,19 +24,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
-// gdbr-check:$1 = generic_tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
+// gdbr-check:$1 = generic_tuple_style_enum::Regular<u16, u32, u64>::Case1(0, 31868, 31868, 31868, 31868)
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
-// gdbr-check:$2 = generic_tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
+// gdbr-check:$2 = generic_tuple_style_enum::Regular<i16, i32, i64>::Case2(0, 286331153, 286331153)
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
-// gdbr-check:$3 = generic_tuple_style_enum::Regular::Case3(0, 6438275382588823897)
+// gdbr-check:$3 = generic_tuple_style_enum::Regular<i16, i32, i64>::Case3(0, 6438275382588823897)
 
 // gdb-command:print univariant
-// gdbg-check:$4 = {{__0 = -1}}
 // gdbr-check:$4 = generic_tuple_style_enum::Univariant<i64>::TheOnlyCase(-1)
 
 
@@ -41,20 +41,16 @@
 // lldb-command:run
 
 // lldb-command:print case1
-// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
 // lldbr-check:(generic_tuple_style_enum::Regular<u16, u32, u64>::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
 
 // lldb-command:print case2
-// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
-// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case2) case2 = Regular<i16, i32, i64>::Case2 { generic_tuple_style_enum::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum::Regular<i16, i32, i64>::Case2: 286331153, generic_tuple_style_enum::Regular<i16, i32, i64>::Case3: 286331153 }
+// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case2) case2 = Regular<i16, i32, i64>::Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 }
 
 // lldb-command:print case3
-// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
-// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case3) case3 = Regular<i16, i32, i64>::Case3 { generic_tuple_style_enum::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum::Regular<i16, i32, i64>::Case2: 6438275382588823897 }
+// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case3) case3 = Regular<i16, i32, i64>::Case3 { Case1: 0, Case2: 6438275382588823897 }
 
 // lldb-command:print univariant
-// lldbg-check:[...]$3 = TheOnlyCase(-1)
-// lldbr-check:(generic_tuple_style_enum::Univariant<i64>) univariant = { generic_tuple_style_enum::TheOnlyCase = { = -1 } }
+// lldbr-check:(generic_tuple_style_enum::Univariant<i64>) univariant = { TheOnlyCase = { = -1 } }
 
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs
index cef7a1cbf1b..ffd402ec936 100644
--- a/src/test/debuginfo/method-on-tuple-struct.rs
+++ b/src/test/debuginfo/method-on-tuple-struct.rs
@@ -74,7 +74,7 @@
 // STACK BY REF
 // lldb-command:print *self
 // lldbg-check:[...]$0 = TupleStruct(100, -100.5)
-// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 100 = -100.5 }
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = TupleStruct(100, -100.5)
 // lldb-command:print arg1
 // lldbg-check:[...]$1 = -1
 // lldbr-check:(isize) arg1 = -1
@@ -86,7 +86,7 @@
 // STACK BY VAL
 // lldb-command:print self
 // lldbg-check:[...]$3 = TupleStruct(100, -100.5)
-// lldbr-check:(method_on_tuple_struct::TupleStruct) self = { = 100 = -100.5 }
+// lldbr-check:(method_on_tuple_struct::TupleStruct) self = TupleStruct(100, -100.5)
 // lldb-command:print arg1
 // lldbg-check:[...]$4 = -3
 // lldbr-check:(isize) arg1 = -3
@@ -98,7 +98,7 @@
 // OWNED BY REF
 // lldb-command:print *self
 // lldbg-check:[...]$6 = TupleStruct(200, -200.5)
-// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 200 = -200.5 }
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = TupleStruct(200, -200.5)
 // lldb-command:print arg1
 // lldbg-check:[...]$7 = -5
 // lldbr-check:(isize) arg1 = -5
@@ -110,7 +110,7 @@
 // OWNED BY VAL
 // lldb-command:print self
 // lldbg-check:[...]$9 = TupleStruct(200, -200.5)
-// lldbr-check:(method_on_tuple_struct::TupleStruct) self = { = 200 = -200.5 }
+// lldbr-check:(method_on_tuple_struct::TupleStruct) self = TupleStruct(200, -200.5)
 // lldb-command:print arg1
 // lldbg-check:[...]$10 = -7
 // lldbr-check:(isize) arg1 = -7
@@ -122,7 +122,7 @@
 // OWNED MOVED
 // lldb-command:print *self
 // lldbg-check:[...]$12 = TupleStruct(200, -200.5)
-// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 200 = -200.5 }
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = TupleStruct(200, -200.5)
 // lldb-command:print arg1
 // lldbg-check:[...]$13 = -9
 // lldbr-check:(isize) arg1 = -9
diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs
index ab9c7e2dd27..ab42b2eff99 100644
--- a/src/test/debuginfo/nil-enum.rs
+++ b/src/test/debuginfo/nil-enum.rs
@@ -14,16 +14,21 @@
 // ignore-lldb
 
 
+// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
+// gdb 8.2.0 crashes on this test case, see
+// https://sourceware.org/bugzilla/show_bug.cgi?id=23626
+// This will be fixed in the next release, which will be >= 8.2.1.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2.1
+
 // compile-flags:-g
 // gdb-command:run
 
 // gdb-command:print first
-// gdbg-check:$1 = {<No data fields>}
-// gdbr-check:$1 = <error reading variable>
+// gdbr-check:$1 = nil_enum::ANilEnum {<No data fields>}
 
 // gdb-command:print second
-// gdbg-check:$2 = {<No data fields>}
-// gdbr-check:$2 = <error reading variable>
+// gdbr-check:$2 = nil_enum::AnotherNilEnum {<No data fields>}
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/recursive-struct-legacy.rs b/src/test/debuginfo/recursive-struct-legacy.rs
new file mode 100644
index 00000000000..ac407ced527
--- /dev/null
+++ b/src/test/debuginfo/recursive-struct-legacy.rs
@@ -0,0 +1,245 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// ignore-lldb
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 7.11.90 - 7.12.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// gdb-command:run
+
+// gdb-command:print stack_unique.value
+// gdb-check:$1 = 0
+// gdbg-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value
+// gdbr-command:print stack_unique.next.val.value
+// gdb-check:$2 = 1
+
+// gdbg-command:print unique_unique->value
+// gdbr-command:print unique_unique.value
+// gdb-check:$3 = 2
+// gdbg-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
+// gdbr-command:print unique_unique.next.val.value
+// gdb-check:$4 = 3
+
+// gdb-command:print vec_unique[0].value
+// gdb-check:$5 = 6.5
+// gdbg-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value
+// gdbr-command:print vec_unique[0].next.val.value
+// gdb-check:$6 = 7.5
+
+// gdbg-command:print borrowed_unique->value
+// gdbr-command:print borrowed_unique.value
+// gdb-check:$7 = 8.5
+// gdbg-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
+// gdbr-command:print borrowed_unique.next.val.value
+// gdb-check:$8 = 9.5
+
+// LONG CYCLE
+// gdb-command:print long_cycle1.value
+// gdb-check:$9 = 20
+// gdbg-command:print long_cycle1.next->value
+// gdbr-command:print long_cycle1.next.value
+// gdb-check:$10 = 21
+// gdbg-command:print long_cycle1.next->next->value
+// gdbr-command:print long_cycle1.next.next.value
+// gdb-check:$11 = 22
+// gdbg-command:print long_cycle1.next->next->next->value
+// gdbr-command:print long_cycle1.next.next.next.value
+// gdb-check:$12 = 23
+
+// gdb-command:print long_cycle2.value
+// gdb-check:$13 = 24
+// gdbg-command:print long_cycle2.next->value
+// gdbr-command:print long_cycle2.next.value
+// gdb-check:$14 = 25
+// gdbg-command:print long_cycle2.next->next->value
+// gdbr-command:print long_cycle2.next.next.value
+// gdb-check:$15 = 26
+
+// gdb-command:print long_cycle3.value
+// gdb-check:$16 = 27
+// gdbg-command:print long_cycle3.next->value
+// gdbr-command:print long_cycle3.next.value
+// gdb-check:$17 = 28
+
+// gdb-command:print long_cycle4.value
+// gdb-check:$18 = 29.5
+
+// gdbg-command:print (*****long_cycle_w_anonymous_types).value
+// gdbr-command:print long_cycle_w_anonymous_types.value
+// gdb-check:$19 = 30
+
+// gdbg-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value
+// gdbr-command:print long_cycle_w_anonymous_types.next.val.value
+// gdb-check:$20 = 31
+
+// gdb-command:continue
+
+#![allow(unused_variables)]
+#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+use self::Opt::{Empty, Val};
+
+enum Opt<T> {
+    Empty,
+    Val { val: T }
+}
+
+struct UniqueNode<T> {
+    next: Opt<Box<UniqueNode<T>>>,
+    value: T
+}
+
+struct LongCycle1<T> {
+    next: Box<LongCycle2<T>>,
+    value: T,
+}
+
+struct LongCycle2<T> {
+    next: Box<LongCycle3<T>>,
+    value: T,
+}
+
+struct LongCycle3<T> {
+    next: Box<LongCycle4<T>>,
+    value: T,
+}
+
+struct LongCycle4<T> {
+    next: Option<Box<LongCycle1<T>>>,
+    value: T,
+}
+
+struct LongCycleWithAnonymousTypes {
+    next: Opt<Box<Box<Box<Box<Box<LongCycleWithAnonymousTypes>>>>>>,
+    value: usize,
+}
+
+// This test case makes sure that recursive structs are properly described. The Node structs are
+// generic so that we can have a new type (that newly needs to be described) for the different
+// cases. The potential problem with recursive types is that the DI generation algorithm gets
+// trapped in an endless loop. To make sure, we actually test this in the different cases, we have
+// to operate on a new type each time, otherwise we would just hit the DI cache for all but the
+// first case.
+
+// The different cases below (stack_*, unique_*, box_*, etc) are set up so that the type description
+// algorithm will enter the type reference cycle that is created by a recursive definition from a
+// different context each time.
+
+// The "long cycle" cases are constructed to span a longer, indirect recursion cycle between types.
+// The different locals will cause the DI algorithm to enter the type reference cycle at different
+// points.
+
+fn main() {
+    let stack_unique: UniqueNode<u16> = UniqueNode {
+        next: Val {
+            val: box UniqueNode {
+                next: Empty,
+                value: 1,
+            }
+        },
+        value: 0,
+    };
+
+    let unique_unique: Box<UniqueNode<u32>> = box UniqueNode {
+        next: Val {
+            val: box UniqueNode {
+                next: Empty,
+                value: 3,
+            }
+        },
+        value: 2,
+    };
+
+    let vec_unique: [UniqueNode<f32>; 1] = [UniqueNode {
+        next: Val {
+            val: box UniqueNode {
+                next: Empty,
+                value: 7.5,
+            }
+        },
+        value: 6.5,
+    }];
+
+    let borrowed_unique: &UniqueNode<f64> = &UniqueNode {
+        next: Val {
+            val: box UniqueNode {
+                next: Empty,
+                value: 9.5,
+            }
+        },
+        value: 8.5,
+    };
+
+    // LONG CYCLE
+    let long_cycle1: LongCycle1<u16> = LongCycle1 {
+        next: box LongCycle2 {
+            next: box LongCycle3 {
+                next: box LongCycle4 {
+                    next: None,
+                    value: 23,
+                },
+                value: 22,
+            },
+            value: 21
+        },
+        value: 20
+    };
+
+    let long_cycle2: LongCycle2<u32> = LongCycle2 {
+        next: box LongCycle3 {
+            next: box LongCycle4 {
+                next: None,
+                value: 26,
+            },
+            value: 25,
+        },
+        value: 24
+    };
+
+    let long_cycle3: LongCycle3<u64> = LongCycle3 {
+        next: box LongCycle4 {
+            next: None,
+            value: 28,
+        },
+        value: 27,
+    };
+
+    let long_cycle4: LongCycle4<f32> = LongCycle4 {
+        next: None,
+        value: 29.5,
+    };
+
+    // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the
+    // `box` chain.
+    let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes {
+        next: Val {
+            val: box box box box box LongCycleWithAnonymousTypes {
+                next: Empty,
+                value: 31,
+            }
+        },
+        value: 30
+    };
+
+    zzz(); // #break
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs
index 75c2feb480e..647f9519789 100644
--- a/src/test/debuginfo/recursive-struct.rs
+++ b/src/test/debuginfo/recursive-struct.rs
@@ -10,7 +10,10 @@
 
 // ignore-tidy-linelength
 // ignore-lldb
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
 
 // compile-flags:-g
 
@@ -18,66 +21,52 @@
 
 // gdb-command:print stack_unique.value
 // gdb-check:$1 = 0
-// gdbg-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value
 // gdbr-command:print stack_unique.next.val.value
 // gdb-check:$2 = 1
 
-// gdbg-command:print unique_unique->value
 // gdbr-command:print unique_unique.value
 // gdb-check:$3 = 2
-// gdbg-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
 // gdbr-command:print unique_unique.next.val.value
 // gdb-check:$4 = 3
 
 // gdb-command:print vec_unique[0].value
 // gdb-check:$5 = 6.5
-// gdbg-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value
 // gdbr-command:print vec_unique[0].next.val.value
 // gdb-check:$6 = 7.5
 
-// gdbg-command:print borrowed_unique->value
 // gdbr-command:print borrowed_unique.value
 // gdb-check:$7 = 8.5
-// gdbg-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
 // gdbr-command:print borrowed_unique.next.val.value
 // gdb-check:$8 = 9.5
 
 // LONG CYCLE
 // gdb-command:print long_cycle1.value
 // gdb-check:$9 = 20
-// gdbg-command:print long_cycle1.next->value
 // gdbr-command:print long_cycle1.next.value
 // gdb-check:$10 = 21
-// gdbg-command:print long_cycle1.next->next->value
 // gdbr-command:print long_cycle1.next.next.value
 // gdb-check:$11 = 22
-// gdbg-command:print long_cycle1.next->next->next->value
 // gdbr-command:print long_cycle1.next.next.next.value
 // gdb-check:$12 = 23
 
 // gdb-command:print long_cycle2.value
 // gdb-check:$13 = 24
-// gdbg-command:print long_cycle2.next->value
 // gdbr-command:print long_cycle2.next.value
 // gdb-check:$14 = 25
-// gdbg-command:print long_cycle2.next->next->value
 // gdbr-command:print long_cycle2.next.next.value
 // gdb-check:$15 = 26
 
 // gdb-command:print long_cycle3.value
 // gdb-check:$16 = 27
-// gdbg-command:print long_cycle3.next->value
 // gdbr-command:print long_cycle3.next.value
 // gdb-check:$17 = 28
 
 // gdb-command:print long_cycle4.value
 // gdb-check:$18 = 29.5
 
-// gdbg-command:print (*****long_cycle_w_anonymous_types).value
 // gdbr-command:print long_cycle_w_anonymous_types.value
 // gdb-check:$19 = 30
 
-// gdbg-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value
 // gdbr-command:print long_cycle_w_anonymous_types.next.val.value
 // gdb-check:$20 = 31
 
diff --git a/src/test/debuginfo/struct-style-enum-legacy.rs b/src/test/debuginfo/struct-style-enum-legacy.rs
new file mode 100644
index 00000000000..fd2c6fa8171
--- /dev/null
+++ b/src/test/debuginfo/struct-style-enum-legacy.rs
@@ -0,0 +1,115 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// min-lldb-version: 310
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 7.11.90 - 7.12.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:set print union on
+// gdb-command:run
+
+// gdb-command:print case1
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
+// gdbr-check:$1 = struct_style_enum_legacy::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
+
+// gdb-command:print case2
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
+// gdbr-check:$2 = struct_style_enum_legacy::Regular::Case2{a: 0, b: 286331153, c: 286331153}
+
+// gdb-command:print case3
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
+// gdbr-check:$3 = struct_style_enum_legacy::Regular::Case3{a: 0, b: 6438275382588823897}
+
+// gdb-command:print univariant
+// gdbg-check:$4 = {{a = -1}}
+// gdbr-check:$4 = struct_style_enum_legacy::Univariant::TheOnlyCase{a: -1}
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+
+// lldb-command:print case1
+// lldbg-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
+// lldbr-check:(struct_style_enum_legacy::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 }
+
+// lldb-command:print case2
+// lldbg-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
+// lldbr-check:(struct_style_enum_legacy::Regular::Case2) case2 = Case2 { struct_style_enum_legacy::Regular::Case1: 0, struct_style_enum_legacy::Regular::Case2: 286331153, struct_style_enum_legacy::Regular::Case3: 286331153 }
+
+// lldb-command:print case3
+// lldbg-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
+// lldbr-check:(struct_style_enum_legacy::Regular::Case3) case3 = Case3 { struct_style_enum_legacy::Regular::Case1: 0, struct_style_enum_legacy::Regular::Case2: 6438275382588823897 }
+
+// lldb-command:print univariant
+// lldbg-check:[...]$3 = TheOnlyCase { a: -1 }
+// lldbr-check:(struct_style_enum_legacy::Univariant) univariant = Univariant { struct_style_enum_legacy::TheOnlyCase: TheOnlyCase { a: -1 } }
+
+#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+use self::Regular::{Case1, Case2, Case3};
+use self::Univariant::TheOnlyCase;
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular {
+    Case1 { a: u64, b: u16, c: u16, d: u16, e: u16},
+    Case2 { a: u64, b: u32, c: u32},
+    Case3 { a: u64, b: u64 }
+}
+
+enum Univariant {
+    TheOnlyCase { a: i64 }
+}
+
+fn main() {
+
+    // In order to avoid endianness trouble all of the following test values consist of a single
+    // repeated byte. This way each interpretation of the union should look the same, no matter if
+    // this is a big or little endian machine.
+
+    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+    // 0b01111100011111000111110001111100 = 2088533116
+    // 0b0111110001111100 = 31868
+    // 0b01111100 = 124
+    let case1 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
+
+    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+    // 0b00010001000100010001000100010001 = 286331153
+    // 0b0001000100010001 = 4369
+    // 0b00010001 = 17
+    let case2 = Case2 { a: 0, b: 286331153, c: 286331153 };
+
+    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+    // 0b01011001010110010101100101011001 = 1499027801
+    // 0b0101100101011001 = 22873
+    // 0b01011001 = 89
+    let case3 = Case3 { a: 0, b: 6438275382588823897 };
+
+    let univariant = TheOnlyCase { a: -1 };
+
+    zzz(); // #break
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs
index 36cd85fb4dc..722ca00e048 100644
--- a/src/test/debuginfo/struct-style-enum.rs
+++ b/src/test/debuginfo/struct-style-enum.rs
@@ -9,8 +9,12 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb and lldb that can
+// read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
+// rust-lldb
 
 // compile-flags:-g
 
@@ -20,19 +24,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
 // gdbr-check:$3 = struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
 
 // gdb-command:print univariant
-// gdbg-check:$4 = {{a = -1}}
 // gdbr-check:$4 = struct_style_enum::Univariant::TheOnlyCase{a: -1}
 
 
@@ -41,20 +41,16 @@
 // lldb-command:run
 
 // lldb-command:print case1
-// lldbg-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
 // lldbr-check:(struct_style_enum::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 }
 
 // lldb-command:print case2
-// lldbg-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
-// lldbr-check:(struct_style_enum::Regular::Case2) case2 = Case2 { struct_style_enum::Regular::Case1: 0, struct_style_enum::Regular::Case2: 286331153, struct_style_enum::Regular::Case3: 286331153 }
+// lldbr-check:(struct_style_enum::Regular::Case2) case2 = Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 }
 
 // lldb-command:print case3
-// lldbg-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
-// lldbr-check:(struct_style_enum::Regular::Case3) case3 = Case3 { struct_style_enum::Regular::Case1: 0, struct_style_enum::Regular::Case2: 6438275382588823897 }
+// lldbr-check:(struct_style_enum::Regular::Case3) case3 = Case3 { Case1: 0, Case2: 6438275382588823897 }
 
 // lldb-command:print univariant
-// lldbg-check:[...]$3 = TheOnlyCase { a: -1 }
-// lldbr-check:(struct_style_enum::Univariant) univariant = Univariant { struct_style_enum::TheOnlyCase: TheOnlyCase { a: -1 } }
+// lldbr-check:(struct_style_enum::Univariant) univariant = Univariant { TheOnlyCase: TheOnlyCase { a: -1 } }
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/tuple-style-enum-legacy.rs b/src/test/debuginfo/tuple-style-enum-legacy.rs
new file mode 100644
index 00000000000..e33f6db534f
--- /dev/null
+++ b/src/test/debuginfo/tuple-style-enum-legacy.rs
@@ -0,0 +1,115 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// min-lldb-version: 310
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 7.11.90 - 7.12.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:set print union on
+// gdb-command:run
+
+// gdb-command:print case1
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
+// gdbr-check:$1 = tuple_style_enum_legacy::Regular::Case1(0, 31868, 31868, 31868, 31868)
+
+// gdb-command:print case2
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
+// gdbr-check:$2 = tuple_style_enum_legacy::Regular::Case2(0, 286331153, 286331153)
+
+// gdb-command:print case3
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
+// gdbr-check:$3 = tuple_style_enum_legacy::Regular::Case3(0, 6438275382588823897)
+
+// gdb-command:print univariant
+// gdbg-check:$4 = {{__0 = -1}}
+// gdbr-check:$4 = tuple_style_enum_legacy::Univariant::TheOnlyCase(-1)
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+
+// lldb-command:print case1
+// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbr-check:(tuple_style_enum_legacy::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
+
+// lldb-command:print case2
+// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbr-check:(tuple_style_enum_legacy::Regular::Case2) case2 = Case2 { tuple_style_enum_legacy::Regular::Case1: 0, tuple_style_enum_legacy::Regular::Case2: 286331153, tuple_style_enum_legacy::Regular::Case3: 286331153 }
+
+// lldb-command:print case3
+// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbr-check:(tuple_style_enum_legacy::Regular::Case3) case3 = Case3 { tuple_style_enum_legacy::Regular::Case1: 0, tuple_style_enum_legacy::Regular::Case2: 6438275382588823897 }
+
+// lldb-command:print univariant
+// lldbg-check:[...]$3 = TheOnlyCase(-1)
+// lldbr-check:(tuple_style_enum_legacy::Univariant) univariant = { tuple_style_enum_legacy::TheOnlyCase = { = -1 } }
+
+#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+use self::Regular::{Case1, Case2, Case3};
+use self::Univariant::TheOnlyCase;
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular {
+    Case1(u64, u16, u16, u16, u16),
+    Case2(u64, u32, u32),
+    Case3(u64, u64)
+}
+
+enum Univariant {
+    TheOnlyCase(i64)
+}
+
+fn main() {
+
+    // In order to avoid endianness trouble all of the following test values consist of a single
+    // repeated byte. This way each interpretation of the union should look the same, no matter if
+    // this is a big or little endian machine.
+
+    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+    // 0b01111100011111000111110001111100 = 2088533116
+    // 0b0111110001111100 = 31868
+    // 0b01111100 = 124
+    let case1 = Case1(0, 31868, 31868, 31868, 31868);
+
+    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+    // 0b00010001000100010001000100010001 = 286331153
+    // 0b0001000100010001 = 4369
+    // 0b00010001 = 17
+    let case2 = Case2(0, 286331153, 286331153);
+
+    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+    // 0b01011001010110010101100101011001 = 1499027801
+    // 0b0101100101011001 = 22873
+    // 0b01011001 = 89
+    let case3 = Case3(0, 6438275382588823897);
+
+    let univariant = TheOnlyCase(-1);
+
+    zzz(); // #break
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs
index 682e74601b0..d976839f08c 100644
--- a/src/test/debuginfo/tuple-style-enum.rs
+++ b/src/test/debuginfo/tuple-style-enum.rs
@@ -9,8 +9,12 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb and lldb that can
+// read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
+// rust-lldb
 
 // compile-flags:-g
 
@@ -20,19 +24,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
 // gdbr-check:$3 = tuple_style_enum::Regular::Case3(0, 6438275382588823897)
 
 // gdb-command:print univariant
-// gdbg-check:$4 = {{__0 = -1}}
 // gdbr-check:$4 = tuple_style_enum::Univariant::TheOnlyCase(-1)
 
 
@@ -41,20 +41,16 @@
 // lldb-command:run
 
 // lldb-command:print case1
-// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
 // lldbr-check:(tuple_style_enum::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
 
 // lldb-command:print case2
-// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
-// lldbr-check:(tuple_style_enum::Regular::Case2) case2 = Case2 { tuple_style_enum::Regular::Case1: 0, tuple_style_enum::Regular::Case2: 286331153, tuple_style_enum::Regular::Case3: 286331153 }
+// lldbr-check:(tuple_style_enum::Regular::Case2) case2 = Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 }
 
 // lldb-command:print case3
-// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
-// lldbr-check:(tuple_style_enum::Regular::Case3) case3 = Case3 { tuple_style_enum::Regular::Case1: 0, tuple_style_enum::Regular::Case2: 6438275382588823897 }
+// lldbr-check:(tuple_style_enum::Regular::Case3) case3 = Case3 { Case1: 0, Case2: 6438275382588823897 }
 
 // lldb-command:print univariant
-// lldbg-check:[...]$3 = TheOnlyCase(-1)
-// lldbr-check:(tuple_style_enum::Univariant) univariant = { tuple_style_enum::TheOnlyCase = { = -1 } }
+// lldbr-check:(tuple_style_enum::Univariant) univariant = { TheOnlyCase = { = -1 } }
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/unique-enum-legacy.rs b/src/test/debuginfo/unique-enum-legacy.rs
new file mode 100644
index 00000000000..91fece334b2
--- /dev/null
+++ b/src/test/debuginfo/unique-enum-legacy.rs
@@ -0,0 +1,98 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// min-lldb-version: 310
+
+// As long as LLVM 5 and LLVM 6 are supported, we want to test the
+// enum debuginfo fallback mode.  Once those are desupported, this
+// test can be removed, as there is another (non-"legacy") test that
+// tests the new mode.
+// ignore-llvm-version: 7.0 - 9.9.9
+// ignore-gdb-version: 7.11.90 - 7.12.9
+// ignore-gdb-version: 8.2 - 9.9
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+
+// gdb-command:print *the_a
+// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
+// gdbr-check:$1 = unique_enum_legacy::ABC::TheA{x: 0, y: 8970181431921507452}
+
+// gdb-command:print *the_b
+// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
+// gdbr-check:$2 = unique_enum_legacy::ABC::TheB(0, 286331153, 286331153)
+
+// gdb-command:print *univariant
+// gdbg-check:$3 = {{__0 = 123234}}
+// gdbr-check:$3 = unique_enum_legacy::Univariant::TheOnlyCase(123234)
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+
+// lldb-command:print *the_a
+// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbr-check:(unique_enum_legacy::ABC::TheA) *the_a = TheA { unique_enum_legacy::ABC::TheA: 0, unique_enum_legacy::ABC::TheB: 8970181431921507452 }
+
+// lldb-command:print *the_b
+// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbr-check:(unique_enum_legacy::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 }
+
+// lldb-command:print *univariant
+// lldbg-check:[...]$2 = TheOnlyCase(123234)
+// lldbr-check:(unique_enum_legacy::Univariant) *univariant = { unique_enum_legacy::TheOnlyCase = { = 123234 } }
+
+#![allow(unused_variables)]
+#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum ABC {
+    TheA { x: i64, y: i64 },
+    TheB (i64, i32, i32),
+}
+
+// This is a special case since it does not have the implicit discriminant field.
+enum Univariant {
+    TheOnlyCase(i64)
+}
+
+fn main() {
+
+    // In order to avoid endianness trouble all of the following test values consist of a single
+    // repeated byte. This way each interpretation of the union should look the same, no matter if
+    // this is a big or little endian machine.
+
+    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+    // 0b01111100011111000111110001111100 = 2088533116
+    // 0b0111110001111100 = 31868
+    // 0b01111100 = 124
+    let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 };
+
+    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+    // 0b00010001000100010001000100010001 = 286331153
+    // 0b0001000100010001 = 4369
+    // 0b00010001 = 17
+    let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153);
+
+    let univariant: Box<_> = box Univariant::TheOnlyCase(123234);
+
+    zzz(); // #break
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs
index 6b62c304513..aab8edc55f7 100644
--- a/src/test/debuginfo/unique-enum.rs
+++ b/src/test/debuginfo/unique-enum.rs
@@ -9,8 +9,12 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
+
+// Require LLVM with DW_TAG_variant_part and a gdb and lldb that can
+// read it.
+// min-system-llvm-version: 7.0
+// min-gdb-version: 8.2
+// rust-lldb
 
 // compile-flags:-g
 
@@ -19,15 +23,12 @@
 // gdb-command:run
 
 // gdb-command:print *the_a
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
 // gdbr-check:$1 = unique_enum::ABC::TheA{x: 0, y: 8970181431921507452}
 
 // gdb-command:print *the_b
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
 // gdbr-check:$2 = unique_enum::ABC::TheB(0, 286331153, 286331153)
 
 // gdb-command:print *univariant
-// gdbg-check:$3 = {{__0 = 123234}}
 // gdbr-check:$3 = unique_enum::Univariant::TheOnlyCase(123234)
 
 
@@ -36,16 +37,13 @@
 // lldb-command:run
 
 // lldb-command:print *the_a
-// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
-// lldbr-check:(unique_enum::ABC::TheA) *the_a = TheA { unique_enum::ABC::TheA: 0, unique_enum::ABC::TheB: 8970181431921507452 }
+// lldbr-check:(unique_enum::ABC::TheA) *the_a = TheA { TheA: 0, TheB: 8970181431921507452 }
 
 // lldb-command:print *the_b
-// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
 // lldbr-check:(unique_enum::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 }
 
 // lldb-command:print *univariant
-// lldbg-check:[...]$2 = TheOnlyCase(123234)
-// lldbr-check:(unique_enum::Univariant) *univariant = { unique_enum::TheOnlyCase = { = 123234 } }
+// lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } }
 
 #![allow(unused_variables)]
 #![feature(box_syntax)]
diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs
index 39bf0c175eb..39267edaac0 100644
--- a/src/test/debuginfo/vec-slices.rs
+++ b/src/test/debuginfo/vec-slices.rs
@@ -99,7 +99,7 @@
 
 // lldb-command:print padded_tuple
 // lldbg-check:[...]$4 = &[(6, 7), (8, 9)]
-// lldbr-check:(&[(i32, i16)]) padded_tuple = { data_ptr = *0x555555554ff0 length = 2 }
+// lldbr-check:(&[(i32, i16)]) padded_tuple = { data_ptr = *0x555555555030 length = 2 }
 
 // lldb-command:print padded_struct
 // lldbg-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 06eeef61a19..f12dd31c402 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -243,6 +243,29 @@ impl EarlyProps {
                     // Ignore if using system LLVM and actual version
                     // is smaller the minimum required version
                     config.system_llvm && &actual_version[..] < min_version
+                } else if line.starts_with("ignore-llvm-version") {
+                    // Syntax is: "ignore-llvm-version <version1> [- <version2>]"
+                    let range_components = line.split(' ')
+                        .skip(1) // Skip the directive.
+                        .map(|s| s.trim())
+                        .filter(|word| !word.is_empty() && word != &"-")
+                        .take(3) // 3 or more = invalid, so take at most 3.
+                        .collect::<Vec<&str>>();
+                    match range_components.len() {
+                        1 => {
+                            &actual_version[..] == range_components[0]
+                        }
+                        2 => {
+                            let v_min = range_components[0];
+                            let v_max = range_components[1];
+                            if v_max < v_min {
+                                panic!("Malformed LLVM version range: max < min")
+                            }
+                            // Ignore if version lies inside of range.
+                            &actual_version[..] >= v_min && &actual_version[..] <= v_max
+                        }
+                        _ => panic!("Malformed LLVM version directive"),
+                    }
                 } else {
                     false
                 }
diff --git a/src/tools/lldb b/src/tools/lldb
-Subproject 7728fa22bebea288abfea3b70cf795c60b93df3
+Subproject 29bf48582812212450f4caf7da1af3f18c52bfe