gdb: Fix testsuite issue in gdb.arch/amd64-disp-step-avx.exp
[external/binutils.git] / gdb / dwarf2read.c
index ff808be..6100438 100644 (file)
@@ -86,6 +86,8 @@
 #include <cmath>
 #include <set>
 #include <forward_list>
+#include "rust-lang.h"
+#include "common/pathstuff.h"
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -762,6 +764,14 @@ struct dwarf2_cu
      whether the DW_AT_ranges attribute came from the skeleton or DWO.  */
   ULONGEST ranges_base = 0;
 
+  /* When reading debug info generated by older versions of rustc, we
+     have to rewrite some union types to be struct types with a
+     variant part.  This rewriting must be done after the CU is fully
+     read in, because otherwise at the point of rewriting some struct
+     type might not have been fully processed.  So, we keep a list of
+     all such types here and process them after expansion.  */
+  std::vector<struct type *> rust_unions;
+
   /* Mark used when releasing cached dies.  */
   unsigned int mark : 1;
 
@@ -1696,31 +1706,36 @@ struct dwarf_block
    and friends.  */
 static int bits_per_byte = 8;
 
-struct nextfield
-{
-  struct nextfield *next;
-  int accessibility;
-  int virtuality;
-  struct field field;
-};
+/* When reading a variant or variant part, we track a bit more
+   information about the field, and store it in an object of this
+   type.  */
 
-struct nextfnfield
+struct variant_field
 {
-  struct nextfnfield *next;
-  struct fn_field fnfield;
+  /* If we see a DW_TAG_variant, then this will be the discriminant
+     value.  */
+  ULONGEST discriminant_value;
+  /* If we see a DW_TAG_variant, then this will be set if this is the
+     default branch.  */
+  bool default_branch;
+  /* While reading a DW_TAG_variant_part, this will be set if this
+     field is the discriminant.  */
+  bool is_discriminant;
 };
 
-struct fnfieldlist
+struct nextfield
 {
-  const char *name;
-  int length;
-  struct nextfnfield *head;
+  int accessibility = 0;
+  int virtuality = 0;
+  /* Extra information to describe a variant or variant part.  */
+  struct variant_field variant {};
+  struct field field {};
 };
 
-struct decl_field_list
+struct fnfieldlist
 {
-  struct decl_field field;
-  struct decl_field_list *next;
+  const char *name = nullptr;
+  std::vector<struct fn_field> fnfields;
 };
 
 /* The routines that read and process dies for a C struct or C++ class
@@ -1729,34 +1744,27 @@ struct decl_field_list
 struct field_info
   {
     /* List of data member and baseclasses fields.  */
-    struct nextfield *fields, *baseclasses;
+    std::vector<struct nextfield> fields;
+    std::vector<struct nextfield> baseclasses;
 
     /* Number of fields (including baseclasses).  */
-    int nfields;
-
-    /* Number of baseclasses.  */
-    int nbaseclasses;
+    int nfields = 0;
 
     /* Set if the accesibility of one of the fields is not public.  */
-    int non_public_fields;
+    int non_public_fields = 0;
 
     /* Member function fieldlist array, contains name of possibly overloaded
        member function, number of overloaded member functions and a pointer
        to the head of the member function field chain.  */
-    struct fnfieldlist *fnfieldlists;
-
-    /* Number of entries in the fnfieldlists array.  */
-    int nfnfields;
+    std::vector<struct fnfieldlist> fnfieldlists;
 
     /* typedefs defined inside this class.  TYPEDEF_FIELD_LIST contains head of
        a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements.  */
-    struct decl_field_list *typedef_field_list;
-    unsigned typedef_field_list_count;
+    std::vector<struct decl_field> typedef_field_list;
 
     /* Nested types defined by this class and the number of elements in this
        list.  */
-    struct decl_field_list *nested_types_list;
-    unsigned nested_types_list_count;
+    std::vector<struct decl_field> nested_types_list;
   };
 
 /* One item on the queue of compilation units to read in full symbols
@@ -8581,19 +8589,13 @@ struct tu_abbrev_offset
   sect_offset abbrev_offset;
 };
 
-/* Helper routine for build_type_psymtabs_1, passed to qsort.  */
+/* Helper routine for build_type_psymtabs_1, passed to std::sort.  */
 
-static int
-sort_tu_by_abbrev_offset (const void *ap, const void *bp)
+static bool
+sort_tu_by_abbrev_offset (const struct tu_abbrev_offset &a,
+                         const struct tu_abbrev_offset &b)
 {
-  const struct tu_abbrev_offset * const *a
-    = (const struct tu_abbrev_offset * const*) ap;
-  const struct tu_abbrev_offset * const *b
-    = (const struct tu_abbrev_offset * const*) bp;
-  sect_offset aoff = (*a)->abbrev_offset;
-  sect_offset boff = (*b)->abbrev_offset;
-
-  return (aoff > boff) - (aoff < boff);
+  return a.abbrev_offset < b.abbrev_offset;
 }
 
 /* Efficiently read all the type units.
@@ -8618,10 +8620,8 @@ static void
 build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
 {
   struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats;
-  struct cleanup *cleanups;
   abbrev_table_up abbrev_table;
   sect_offset abbrev_offset;
-  struct tu_abbrev_offset *sorted_by_abbrev;
   int i;
 
   /* It's up to the caller to not call us multiple times.  */
@@ -8654,8 +8654,8 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
 
   /* Sort in a separate table to maintain the order of all_type_units
      for .gdb_index: TU indices directly index all_type_units.  */
-  sorted_by_abbrev = XNEWVEC (struct tu_abbrev_offset,
-                             dwarf2_per_objfile->n_type_units);
+  std::vector<struct tu_abbrev_offset> sorted_by_abbrev
+    (dwarf2_per_objfile->n_type_units);
   for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
     {
       struct signatured_type *sig_type = dwarf2_per_objfile->all_type_units[i];
@@ -8666,9 +8666,8 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
                            sig_type->per_cu.section,
                            sig_type->per_cu.sect_off);
     }
-  cleanups = make_cleanup (xfree, sorted_by_abbrev);
-  qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units,
-        sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset);
+  std::sort (sorted_by_abbrev.begin (), sorted_by_abbrev.end (),
+            sort_tu_by_abbrev_offset);
 
   abbrev_offset = (sect_offset) ~(unsigned) 0;
 
@@ -8691,8 +8690,6 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
       init_cutu_and_read_dies (&tu->sig_type->per_cu, abbrev_table.get (),
                               0, 0, build_type_psymtabs_reader, NULL);
     }
-
-  do_cleanups (cleanups);
 }
 
 /* Print collected type unit statistics.  */
@@ -10318,6 +10315,305 @@ fixup_go_packaging (struct dwarf2_cu *cu)
     }
 }
 
+/* Allocate a fully-qualified name consisting of the two parts on the
+   obstack.  */
+
+static const char *
+rust_fully_qualify (struct obstack *obstack, const char *p1, const char *p2)
+{
+  return obconcat (obstack, p1, "::", p2, (char *) NULL);
+}
+
+/* A helper that allocates a struct discriminant_info to attach to a
+   union type.  */
+
+static struct discriminant_info *
+alloc_discriminant_info (struct type *type, int discriminant_index,
+                        int default_index)
+{
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+  gdb_assert (discriminant_index == -1
+             || (discriminant_index >= 0
+                 && discriminant_index < TYPE_NFIELDS (type)));
+  gdb_assert (default_index == -1
+             || (default_index >= 0 && default_index < TYPE_NFIELDS (type)));
+
+  TYPE_FLAG_DISCRIMINATED_UNION (type) = 1;
+
+  struct discriminant_info *disc
+    = ((struct discriminant_info *)
+       TYPE_ZALLOC (type,
+                   offsetof (struct discriminant_info, discriminants)
+                   + TYPE_NFIELDS (type) * sizeof (disc->discriminants[0])));
+  disc->default_index = default_index;
+  disc->discriminant_index = discriminant_index;
+
+  struct dynamic_prop prop;
+  prop.kind = PROP_UNDEFINED;
+  prop.data.baton = disc;
+
+  add_dyn_prop (DYN_PROP_DISCRIMINATED, prop, type);
+
+  return disc;
+}
+
+/* Some versions of rustc emitted enums in an unusual way.
+
+   Ordinary enums were emitted as unions.  The first element of each
+   structure in the union was named "RUST$ENUM$DISR".  This element
+   held the discriminant.
+
+   These versions of Rust also implemented the "non-zero"
+   optimization.  When the enum had two values, and one is empty and
+   the other holds a pointer that cannot be zero, the pointer is used
+   as the discriminant, with a zero value meaning the empty variant.
+   Here, the union's first member is of the form
+   RUST$ENCODED$ENUM$<fieldno>$<fieldno>$...$<variantname>
+   where the fieldnos are the indices of the fields that should be
+   traversed in order to find the field (which may be several fields deep)
+   and the variantname is the name of the variant of the case when the
+   field is zero.
+
+   This function recognizes whether TYPE is of one of these forms,
+   and, if so, smashes it to be a variant type.  */
+
+static void
+quirk_rust_enum (struct type *type, struct objfile *objfile)
+{
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+
+  /* We don't need to deal with empty enums.  */
+  if (TYPE_NFIELDS (type) == 0)
+    return;
+
+#define RUST_ENUM_PREFIX "RUST$ENCODED$ENUM$"
+  if (TYPE_NFIELDS (type) == 1
+      && startswith (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX))
+    {
+      const char *name = TYPE_FIELD_NAME (type, 0) + strlen (RUST_ENUM_PREFIX);
+
+      /* Decode the field name to find the offset of the
+        discriminant.  */
+      ULONGEST bit_offset = 0;
+      struct type *field_type = TYPE_FIELD_TYPE (type, 0);
+      while (name[0] >= '0' && name[0] <= '9')
+       {
+         char *tail;
+         unsigned long index = strtoul (name, &tail, 10);
+         name = tail;
+         if (*name != '$'
+             || index >= TYPE_NFIELDS (field_type)
+             || (TYPE_FIELD_LOC_KIND (field_type, index)
+                 != FIELD_LOC_KIND_BITPOS))
+           {
+             complaint (&symfile_complaints,
+                        _("Could not parse Rust enum encoding string \"%s\""
+                          "[in module %s]"),
+                        TYPE_FIELD_NAME (type, 0),
+                        objfile_name (objfile));
+             return;
+           }
+         ++name;
+
+         bit_offset += TYPE_FIELD_BITPOS (field_type, index);
+         field_type = TYPE_FIELD_TYPE (field_type, index);
+       }
+
+      /* Make a union to hold the variants.  */
+      struct type *union_type = alloc_type (objfile);
+      TYPE_CODE (union_type) = TYPE_CODE_UNION;
+      TYPE_NFIELDS (union_type) = 3;
+      TYPE_FIELDS (union_type)
+       = (struct field *) TYPE_ZALLOC (type, 3 * sizeof (struct field));
+      TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+
+      /* Put the discriminant must at index 0.  */
+      TYPE_FIELD_TYPE (union_type, 0) = field_type;
+      TYPE_FIELD_ARTIFICIAL (union_type, 0) = 1;
+      TYPE_FIELD_NAME (union_type, 0) = "<<discriminant>>";
+      SET_FIELD_BITPOS (TYPE_FIELD (union_type, 0), bit_offset);
+
+      /* The order of fields doesn't really matter, so put the real
+        field at index 1 and the data-less field at index 2.  */
+      struct discriminant_info *disc
+       = alloc_discriminant_info (union_type, 0, 1);
+      TYPE_FIELD (union_type, 1) = TYPE_FIELD (type, 0);
+      TYPE_FIELD_NAME (union_type, 1)
+       = rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (union_type, 1)));
+      TYPE_NAME (TYPE_FIELD_TYPE (union_type, 1))
+       = rust_fully_qualify (&objfile->objfile_obstack, TYPE_NAME (type),
+                             TYPE_FIELD_NAME (union_type, 1));
+
+      const char *dataless_name
+       = rust_fully_qualify (&objfile->objfile_obstack, TYPE_NAME (type),
+                             name);
+      struct type *dataless_type = init_type (objfile, TYPE_CODE_VOID, 0,
+                                             dataless_name);
+      TYPE_FIELD_TYPE (union_type, 2) = dataless_type;
+      /* NAME points into the original discriminant name, which
+        already has the correct lifetime.  */
+      TYPE_FIELD_NAME (union_type, 2) = name;
+      SET_FIELD_BITPOS (TYPE_FIELD (union_type, 2), 0);
+      disc->discriminants[2] = 0;
+
+      /* Smash this type to be a structure type.  We have to do this
+        because the type has already been recorded.  */
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+      TYPE_NFIELDS (type) = 1;
+      TYPE_FIELDS (type)
+       = (struct field *) TYPE_ZALLOC (type, sizeof (struct field));
+
+      /* Install the variant part.  */
+      TYPE_FIELD_TYPE (type, 0) = union_type;
+      SET_FIELD_BITPOS (TYPE_FIELD (type, 0), 0);
+      TYPE_FIELD_NAME (type, 0) = "<<variants>>";
+    }
+  else if (TYPE_NFIELDS (type) == 1)
+    {
+      /* We assume that a union with a single field is a univariant
+        enum.  */
+      /* Smash this type to be a structure type.  We have to do this
+        because the type has already been recorded.  */
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+      /* Make a union to hold the variants.  */
+      struct type *union_type = alloc_type (objfile);
+      TYPE_CODE (union_type) = TYPE_CODE_UNION;
+      TYPE_NFIELDS (union_type) = TYPE_NFIELDS (type);
+      TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+      TYPE_FIELDS (union_type) = TYPE_FIELDS (type);
+
+      struct type *field_type = TYPE_FIELD_TYPE (union_type, 0);
+      const char *variant_name
+       = rust_last_path_segment (TYPE_NAME (field_type));
+      TYPE_FIELD_NAME (union_type, 0) = variant_name;
+      TYPE_NAME (field_type)
+       = rust_fully_qualify (&objfile->objfile_obstack,
+                             TYPE_NAME (type), variant_name);
+
+      /* Install the union in the outer struct type.  */
+      TYPE_NFIELDS (type) = 1;
+      TYPE_FIELDS (type)
+       = (struct field *) TYPE_ZALLOC (union_type, sizeof (struct field));
+      TYPE_FIELD_TYPE (type, 0) = union_type;
+      TYPE_FIELD_NAME (type, 0) = "<<variants>>";
+      SET_FIELD_BITPOS (TYPE_FIELD (type, 0), 0);
+
+      alloc_discriminant_info (union_type, -1, 0);
+    }
+  else
+    {
+      struct type *disr_type = nullptr;
+      for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+       {
+         disr_type = TYPE_FIELD_TYPE (type, i);
+
+         if (TYPE_NFIELDS (disr_type) == 0)
+           {
+             /* Could be data-less variant, so keep going.  */
+           }
+         else if (strcmp (TYPE_FIELD_NAME (disr_type, 0),
+                          "RUST$ENUM$DISR") != 0)
+           {
+             /* Not a Rust enum.  */
+             return;
+           }
+         else
+           {
+             /* Found one.  */
+             break;
+           }
+       }
+
+      /* If we got here without a discriminant, then it's probably
+        just a union.  */
+      if (disr_type == nullptr)
+       return;
+
+      /* Smash this type to be a structure type.  We have to do this
+        because the type has already been recorded.  */
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+      /* Make a union to hold the variants.  */
+      struct field *disr_field = &TYPE_FIELD (disr_type, 0);
+      struct type *union_type = alloc_type (objfile);
+      TYPE_CODE (union_type) = TYPE_CODE_UNION;
+      TYPE_NFIELDS (union_type) = 1 + TYPE_NFIELDS (type);
+      TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+      TYPE_FIELDS (union_type)
+       = (struct field *) TYPE_ZALLOC (union_type,
+                                       (TYPE_NFIELDS (union_type)
+                                        * sizeof (struct field)));
+
+      memcpy (TYPE_FIELDS (union_type) + 1, TYPE_FIELDS (type),
+             TYPE_NFIELDS (type) * sizeof (struct field));
+
+      /* Install the discriminant at index 0 in the union.  */
+      TYPE_FIELD (union_type, 0) = *disr_field;
+      TYPE_FIELD_ARTIFICIAL (union_type, 0) = 1;
+      TYPE_FIELD_NAME (union_type, 0) = "<<discriminant>>";
+
+      /* Install the union in the outer struct type.  */
+      TYPE_FIELD_TYPE (type, 0) = union_type;
+      TYPE_FIELD_NAME (type, 0) = "<<variants>>";
+      TYPE_NFIELDS (type) = 1;
+
+      /* Set the size and offset of the union type.  */
+      SET_FIELD_BITPOS (TYPE_FIELD (type, 0), 0);
+
+      /* We need a way to find the correct discriminant given a
+        variant name.  For convenience we build a map here.  */
+      struct type *enum_type = FIELD_TYPE (*disr_field);
+      std::unordered_map<std::string, ULONGEST> discriminant_map;
+      for (int i = 0; i < TYPE_NFIELDS (enum_type); ++i)
+       {
+         if (TYPE_FIELD_LOC_KIND (enum_type, i) == FIELD_LOC_KIND_ENUMVAL)
+           {
+             const char *name
+               = rust_last_path_segment (TYPE_FIELD_NAME (enum_type, i));
+             discriminant_map[name] = TYPE_FIELD_ENUMVAL (enum_type, i);
+           }
+       }
+
+      int n_fields = TYPE_NFIELDS (union_type);
+      struct discriminant_info *disc
+       = alloc_discriminant_info (union_type, 0, -1);
+      /* Skip the discriminant here.  */
+      for (int i = 1; i < n_fields; ++i)
+       {
+         /* Find the final word in the name of this variant's type.
+            That name can be used to look up the correct
+            discriminant.  */
+         const char *variant_name
+           = rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (union_type,
+                                                                 i)));
+
+         auto iter = discriminant_map.find (variant_name);
+         if (iter != discriminant_map.end ())
+           disc->discriminants[i] = iter->second;
+
+         /* Remove the discriminant field.  */
+         struct type *sub_type = TYPE_FIELD_TYPE (union_type, i);
+         --TYPE_NFIELDS (sub_type);
+         ++TYPE_FIELDS (sub_type);
+         TYPE_FIELD_NAME (union_type, i) = variant_name;
+         TYPE_NAME (sub_type)
+           = rust_fully_qualify (&objfile->objfile_obstack,
+                                 TYPE_NAME (type), variant_name);
+       }
+    }
+}
+
+/* Rewrite some Rust unions to be structures with variants parts.  */
+
+static void
+rust_union_quirks (struct dwarf2_cu *cu)
+{
+  gdb_assert (cu->language == language_rust);
+  for (struct type *type : cu->rust_unions)
+    quirk_rust_enum (type, cu->per_cu->dwarf2_per_objfile->objfile);
+}
+
 /* Return the symtab for PER_CU.  This works properly regardless of
    whether we're using the index or psymtabs.  */
 
@@ -10502,6 +10798,9 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu,
      physnames.  */
   compute_delayed_physnames (cu);
 
+  if (cu->language == language_rust)
+    rust_union_quirks (cu);
+
   /* Some compilers don't define a DW_AT_high_pc attribute for the
      compilation unit.  If the DW_AT_high_pc is missing, synthesize
      it, by scanning the DIE's below the compilation unit.  */
@@ -10604,6 +10903,9 @@ process_full_type_unit (struct dwarf2_per_cu_data *per_cu,
      physnames.  */
   compute_delayed_physnames (cu);
 
+  if (cu->language == language_rust)
+    rust_union_quirks (cu);
+
   /* TUs share symbol tables.
      If this is the first TU to use this symtab, complete the construction
      of it with end_expandable_symtab.  Otherwise, complete the addition of
@@ -15157,21 +15459,17 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
   struct field *fp;
   const char *fieldname = "";
 
-  /* Allocate a new field list entry and link it in.  */
-  new_field = XNEW (struct nextfield);
-  make_cleanup (xfree, new_field);
-  memset (new_field, 0, sizeof (struct nextfield));
-
   if (die->tag == DW_TAG_inheritance)
     {
-      new_field->next = fip->baseclasses;
-      fip->baseclasses = new_field;
+      fip->baseclasses.emplace_back ();
+      new_field = &fip->baseclasses.back ();
     }
   else
     {
-      new_field->next = fip->fields;
-      fip->fields = new_field;
+      fip->fields.emplace_back ();
+      new_field = &fip->fields.back ();
     }
+
   fip->nfields++;
 
   attr = dwarf2_attr (die, DW_AT_accessibility, cu);
@@ -15331,8 +15629,21 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
       FIELD_BITSIZE (*fp) = 0;
       FIELD_TYPE (*fp) = die_type (die, cu);
       FIELD_NAME (*fp) = type_name_no_tag (fp->type);
-      fip->nbaseclasses++;
     }
+  else if (die->tag == DW_TAG_variant_part)
+    {
+      /* process_structure_scope will treat this DIE as a union.  */
+      process_structure_scope (die, cu);
+
+      /* The variant part is relative to the start of the enclosing
+        structure.  */
+      SET_FIELD_BITPOS (*fp, 0);
+      fp->type = get_die_type (die, cu);
+      fp->artificial = 1;
+      fp->name = "<<variant>>";
+    }
+  else
+    gdb_assert_not_reached ("missing case in dwarf2_add_field");
 }
 
 /* Can the type given by DIE define another type?  */
@@ -15360,20 +15671,14 @@ static void
 dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
                      struct dwarf2_cu *cu)
 {
-  struct decl_field_list *new_field;
-  struct decl_field *fp;
-
-  /* Allocate a new field list entry and link it in.  */
-  new_field = XCNEW (struct decl_field_list);
-  make_cleanup (xfree, new_field);
+  struct decl_field fp;
+  memset (&fp, 0, sizeof (fp));
 
   gdb_assert (type_can_define_types (die));
 
-  fp = &new_field->field;
-
   /* Get name of field.  NULL is okay here, meaning an anonymous type.  */
-  fp->name = dwarf2_name (die, cu);
-  fp->type = read_type_die (die, cu);
+  fp.name = dwarf2_name (die, cu);
+  fp.type = read_type_die (die, cu);
 
   /* Save accessibility.  */
   enum dwarf_access_attribute accessibility;
@@ -15388,10 +15693,10 @@ dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
       /* The assumed value if neither private nor protected.  */
       break;
     case DW_ACCESS_private:
-      fp->is_private = 1;
+      fp.is_private = 1;
       break;
     case DW_ACCESS_protected:
-      fp->is_protected = 1;
+      fp.is_protected = 1;
       break;
     default:
       complaint (&symfile_complaints,
@@ -15399,17 +15704,9 @@ dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
     }
 
   if (die->tag == DW_TAG_typedef)
-    {
-      new_field->next = fip->typedef_field_list;
-      fip->typedef_field_list = new_field;
-      fip->typedef_field_list_count++;
-    }
+    fip->typedef_field_list.push_back (fp);
   else
-    {
-      new_field->next = fip->nested_types_list;
-      fip->nested_types_list = new_field;
-      fip->nested_types_list_count++;
-    }
+    fip->nested_types_list.push_back (fp);
 }
 
 /* Create the vector of fields, and attach it to the type.  */
@@ -15424,8 +15721,7 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
      and create blank accessibility bitfields if necessary.  */
   TYPE_NFIELDS (type) = nfields;
   TYPE_FIELDS (type) = (struct field *)
-    TYPE_ALLOC (type, sizeof (struct field) * nfields);
-  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+    TYPE_ZALLOC (type, sizeof (struct field) * nfields);
 
   if (fip->non_public_fields && cu->language != language_ada)
     {
@@ -15446,47 +15742,53 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
 
   /* If the type has baseclasses, allocate and clear a bit vector for
      TYPE_FIELD_VIRTUAL_BITS.  */
-  if (fip->nbaseclasses && cu->language != language_ada)
+  if (!fip->baseclasses.empty () && cu->language != language_ada)
     {
-      int num_bytes = B_BYTES (fip->nbaseclasses);
+      int num_bytes = B_BYTES (fip->baseclasses.size ());
       unsigned char *pointer;
 
       ALLOCATE_CPLUS_STRUCT_TYPE (type);
       pointer = (unsigned char *) TYPE_ALLOC (type, num_bytes);
       TYPE_FIELD_VIRTUAL_BITS (type) = pointer;
-      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), fip->nbaseclasses);
-      TYPE_N_BASECLASSES (type) = fip->nbaseclasses;
+      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), fip->baseclasses.size ());
+      TYPE_N_BASECLASSES (type) = fip->baseclasses.size ();
     }
 
-  /* Copy the saved-up fields into the field vector.  Start from the head of
-     the list, adding to the tail of the field array, so that they end up in
-     the same order in the array in which they were added to the list.  */
-  while (nfields-- > 0)
+  if (TYPE_FLAG_DISCRIMINATED_UNION (type))
     {
-      struct nextfield *fieldp;
+      struct discriminant_info *di = alloc_discriminant_info (type, -1, -1);
 
-      if (fip->fields)
+      for (int index = 0; index < nfields; ++index)
        {
-         fieldp = fip->fields;
-         fip->fields = fieldp->next;
-       }
-      else
-       {
-         fieldp = fip->baseclasses;
-         fip->baseclasses = fieldp->next;
+         struct nextfield &field = fip->fields[index];
+
+         if (field.variant.is_discriminant)
+           di->discriminant_index = index;
+         else if (field.variant.default_branch)
+           di->default_index = index;
+         else
+           di->discriminants[index] = field.variant.discriminant_value;
        }
+    }
+
+  /* Copy the saved-up fields into the field vector.  */
+  for (int i = 0; i < nfields; ++i)
+    {
+      struct nextfield &field
+       = ((i < fip->baseclasses.size ()) ? fip->baseclasses[i]
+          : fip->fields[i - fip->baseclasses.size ()]);
 
-      TYPE_FIELD (type, nfields) = fieldp->field;
-      switch (fieldp->accessibility)
+      TYPE_FIELD (type, i) = field.field;
+      switch (field.accessibility)
        {
        case DW_ACCESS_private:
          if (cu->language != language_ada)
-           SET_TYPE_FIELD_PRIVATE (type, nfields);
+           SET_TYPE_FIELD_PRIVATE (type, i);
          break;
 
        case DW_ACCESS_protected:
          if (cu->language != language_ada)
-           SET_TYPE_FIELD_PROTECTED (type, nfields);
+           SET_TYPE_FIELD_PROTECTED (type, i);
          break;
 
        case DW_ACCESS_public:
@@ -15496,19 +15798,19 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
          /* Unknown accessibility.  Complain and treat it as public.  */
          {
            complaint (&symfile_complaints, _("unsupported accessibility %d"),
-                      fieldp->accessibility);
+                      field.accessibility);
          }
          break;
        }
-      if (nfields < fip->nbaseclasses)
+      if (i < fip->baseclasses.size ())
        {
-         switch (fieldp->virtuality)
+         switch (field.virtuality)
            {
            case DW_VIRTUALITY_virtual:
            case DW_VIRTUALITY_pure_virtual:
              if (cu->language == language_ada)
                error (_("unexpected virtuality in component of Ada type"));
-             SET_TYPE_FIELD_VIRTUAL (type, nfields);
+             SET_TYPE_FIELD_VIRTUAL (type, i);
              break;
            }
        }
@@ -15551,11 +15853,10 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
 {
   struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
   struct attribute *attr;
-  struct fnfieldlist *flp;
   int i;
+  struct fnfieldlist *flp = nullptr;
   struct fn_field *fnp;
   const char *fieldname;
-  struct nextfnfield *new_fnfield;
   struct type *this_type;
   enum dwarf_access_attribute accessibility;
 
@@ -15568,51 +15869,33 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
     return;
 
   /* Look up member function name in fieldlist.  */
-  for (i = 0; i < fip->nfnfields; i++)
+  for (i = 0; i < fip->fnfieldlists.size (); i++)
     {
       if (strcmp (fip->fnfieldlists[i].name, fieldname) == 0)
-       break;
+       {
+         flp = &fip->fnfieldlists[i];
+         break;
+       }
     }
 
-  /* Create new list element if necessary.  */
-  if (i < fip->nfnfields)
-    flp = &fip->fnfieldlists[i];
-  else
+  /* Create a new fnfieldlist if necessary.  */
+  if (flp == nullptr)
     {
-      if ((fip->nfnfields % DW_FIELD_ALLOC_CHUNK) == 0)
-       {
-         fip->fnfieldlists = (struct fnfieldlist *)
-           xrealloc (fip->fnfieldlists,
-                     (fip->nfnfields + DW_FIELD_ALLOC_CHUNK)
-                     * sizeof (struct fnfieldlist));
-         if (fip->nfnfields == 0)
-           make_cleanup (free_current_contents, &fip->fnfieldlists);
-       }
-      flp = &fip->fnfieldlists[fip->nfnfields];
+      fip->fnfieldlists.emplace_back ();
+      flp = &fip->fnfieldlists.back ();
       flp->name = fieldname;
-      flp->length = 0;
-      flp->head = NULL;
-      i = fip->nfnfields++;
+      i = fip->fnfieldlists.size () - 1;
     }
 
-  /* Create a new member function field and chain it to the field list
-     entry.  */
-  new_fnfield = XNEW (struct nextfnfield);
-  make_cleanup (xfree, new_fnfield);
-  memset (new_fnfield, 0, sizeof (struct nextfnfield));
-  new_fnfield->next = flp->head;
-  flp->head = new_fnfield;
-  flp->length++;
-
-  /* Fill in the member function field info.  */
-  fnp = &new_fnfield->fnfield;
+  /* Create a new member function field and add it to the vector of
+     fnfieldlists.  */
+  flp->fnfields.emplace_back ();
+  fnp = &flp->fnfields.back ();
 
   /* Delay processing of the physname until later.  */
   if (cu->language == language_cplus)
-    {
-      add_to_method_list (type, i, flp->length - 1, fieldname,
-                         die, cu);
-    }
+    add_to_method_list (type, i, flp->fnfields.size () - 1, fieldname,
+                       die, cu);
   else
     {
       const char *physname = dwarf2_physname (fieldname, die, cu);
@@ -15759,31 +16042,29 @@ static void
 dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type,
                                 struct dwarf2_cu *cu)
 {
-  struct fnfieldlist *flp;
-  int i;
-
   if (cu->language == language_ada)
     error (_("unexpected member functions in Ada type"));
 
   ALLOCATE_CPLUS_STRUCT_TYPE (type);
   TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
-    TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * fip->nfnfields);
+    TYPE_ALLOC (type,
+               sizeof (struct fn_fieldlist) * fip->fnfieldlists.size ());
 
-  for (i = 0, flp = fip->fnfieldlists; i < fip->nfnfields; i++, flp++)
+  for (int i = 0; i < fip->fnfieldlists.size (); i++)
     {
-      struct nextfnfield *nfp = flp->head;
+      struct fnfieldlist &nf = fip->fnfieldlists[i];
       struct fn_fieldlist *fn_flp = &TYPE_FN_FIELDLIST (type, i);
-      int k;
 
-      TYPE_FN_FIELDLIST_NAME (type, i) = flp->name;
-      TYPE_FN_FIELDLIST_LENGTH (type, i) = flp->length;
+      TYPE_FN_FIELDLIST_NAME (type, i) = nf.name;
+      TYPE_FN_FIELDLIST_LENGTH (type, i) = nf.fnfields.size ();
       fn_flp->fn_fields = (struct fn_field *)
-       TYPE_ALLOC (type, sizeof (struct fn_field) * flp->length);
-      for (k = flp->length; (k--, nfp); nfp = nfp->next)
-       fn_flp->fn_fields[k] = nfp->fnfield;
+       TYPE_ALLOC (type, sizeof (struct fn_field) * nf.fnfields.size ());
+
+      for (int k = 0; k < nf.fnfields.size (); ++k)
+       fn_flp->fn_fields[k] = nf.fnfields[k];
     }
 
-  TYPE_NFN_FIELDS (type) = fip->nfnfields;
+  TYPE_NFN_FIELDS (type) = fip->fnfieldlists.size ();
 }
 
 /* Returns non-zero if NAME is the name of a vtable member in CU's
@@ -15919,6 +16200,11 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
     {
       TYPE_CODE (type) = TYPE_CODE_UNION;
     }
+  else if (die->tag == DW_TAG_variant_part)
+    {
+      TYPE_CODE (type) = TYPE_CODE_UNION;
+      TYPE_FLAG_DISCRIMINATED_UNION (type) = 1;
+    }
   else
     {
       TYPE_CODE (type) = TYPE_CODE_STRUCT;
@@ -15978,6 +16264,92 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
   return type;
 }
 
+/* A helper for process_structure_scope that handles a single member
+   DIE.  */
+
+static void
+handle_struct_member_die (struct die_info *child_die, struct type *type,
+                         struct field_info *fi,
+                         std::vector<struct symbol *> *template_args,
+                         struct dwarf2_cu *cu)
+{
+  if (child_die->tag == DW_TAG_member
+      || child_die->tag == DW_TAG_variable
+      || child_die->tag == DW_TAG_variant_part)
+    {
+      /* NOTE: carlton/2002-11-05: A C++ static data member
+        should be a DW_TAG_member that is a declaration, but
+        all versions of G++ as of this writing (so through at
+        least 3.2.1) incorrectly generate DW_TAG_variable
+        tags for them instead.  */
+      dwarf2_add_field (fi, child_die, cu);
+    }
+  else if (child_die->tag == DW_TAG_subprogram)
+    {
+      /* Rust doesn't have member functions in the C++ sense.
+        However, it does emit ordinary functions as children
+        of a struct DIE.  */
+      if (cu->language == language_rust)
+       read_func_scope (child_die, cu);
+      else
+       {
+         /* C++ member function.  */
+         dwarf2_add_member_fn (fi, child_die, type, cu);
+       }
+    }
+  else if (child_die->tag == DW_TAG_inheritance)
+    {
+      /* C++ base class field.  */
+      dwarf2_add_field (fi, child_die, cu);
+    }
+  else if (type_can_define_types (child_die))
+    dwarf2_add_type_defn (fi, child_die, cu);
+  else if (child_die->tag == DW_TAG_template_type_param
+          || child_die->tag == DW_TAG_template_value_param)
+    {
+      struct symbol *arg = new_symbol (child_die, NULL, cu);
+
+      if (arg != NULL)
+       template_args->push_back (arg);
+    }
+  else if (child_die->tag == DW_TAG_variant)
+    {
+      /* In a variant we want to get the discriminant and also add a
+        field for our sole member child.  */
+      struct attribute *discr = dwarf2_attr (child_die, DW_AT_discr_value, cu);
+
+      for (struct die_info *variant_child = child_die->child;
+          variant_child != NULL;
+          variant_child = sibling_die (variant_child))
+       {
+         if (variant_child->tag == DW_TAG_member)
+           {
+             handle_struct_member_die (variant_child, type, fi,
+                                       template_args, cu);
+             /* Only handle the one.  */
+             break;
+           }
+       }
+
+      /* We don't handle this but we might as well report it if we see
+        it.  */
+      if (dwarf2_attr (child_die, DW_AT_discr_list, cu) != nullptr)
+         complaint (&symfile_complaints,
+                    _("DW_AT_discr_list is not supported yet"
+                      " - DIE at %s [in module %s]"),
+                    sect_offset_str (child_die->sect_off),
+                    objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+
+      /* The first field was just added, so we can stash the
+        discriminant there.  */
+      gdb_assert (!fi->fields.empty ());
+      if (discr == NULL)
+       fi->fields.back ().variant.default_branch = true;
+      else
+       fi->fields.back ().variant.discriminant_value = DW_UNSND (discr);
+    }
+}
+
 /* Finish creating a structure or union type, including filling in
    its members and creating a symbol for it.  */
 
@@ -15992,56 +16364,52 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (type == NULL)
     type = read_structure_type (die, cu);
 
+  /* When reading a DW_TAG_variant_part, we need to notice when we
+     read the discriminant member, so we can record it later in the
+     discriminant_info.  */
+  bool is_variant_part = TYPE_FLAG_DISCRIMINATED_UNION (type);
+  sect_offset discr_offset;
+
+  if (is_variant_part)
+    {
+      struct attribute *discr = dwarf2_attr (die, DW_AT_discr, cu);
+      if (discr == NULL)
+       {
+         /* Maybe it's a univariant form, an extension we support.
+            In this case arrange not to check the offset.  */
+         is_variant_part = false;
+       }
+      else if (attr_form_is_ref (discr))
+       {
+         struct dwarf2_cu *target_cu = cu;
+         struct die_info *target_die = follow_die_ref (die, discr, &target_cu);
+
+         discr_offset = target_die->sect_off;
+       }
+      else
+       {
+         complaint (&symfile_complaints,
+                    _("DW_AT_discr does not have DIE reference form"
+                      " - DIE at %s [in module %s]"),
+                    sect_offset_str (die->sect_off),
+                    objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+         is_variant_part = false;
+       }
+    }
+
   if (die->child != NULL && ! die_is_declaration (die, cu))
     {
       struct field_info fi;
       std::vector<struct symbol *> template_args;
-      struct cleanup *back_to = make_cleanup (null_cleanup, 0);
-
-      memset (&fi, 0, sizeof (struct field_info));
 
       child_die = die->child;
 
       while (child_die && child_die->tag)
        {
-         if (child_die->tag == DW_TAG_member
-             || child_die->tag == DW_TAG_variable)
-           {
-             /* NOTE: carlton/2002-11-05: A C++ static data member
-                should be a DW_TAG_member that is a declaration, but
-                all versions of G++ as of this writing (so through at
-                least 3.2.1) incorrectly generate DW_TAG_variable
-                tags for them instead.  */
-             dwarf2_add_field (&fi, child_die, cu);
-           }
-         else if (child_die->tag == DW_TAG_subprogram)
-           {
-             /* Rust doesn't have member functions in the C++ sense.
-                However, it does emit ordinary functions as children
-                of a struct DIE.  */
-             if (cu->language == language_rust)
-               read_func_scope (child_die, cu);
-             else
-               {
-                 /* C++ member function.  */
-                 dwarf2_add_member_fn (&fi, child_die, type, cu);
-               }
-           }
-         else if (child_die->tag == DW_TAG_inheritance)
-           {
-             /* C++ base class field.  */
-             dwarf2_add_field (&fi, child_die, cu);
-           }
-         else if (type_can_define_types (child_die))
-           dwarf2_add_type_defn (&fi, child_die, cu);
-         else if (child_die->tag == DW_TAG_template_type_param
-                  || child_die->tag == DW_TAG_template_value_param)
-           {
-             struct symbol *arg = new_symbol (child_die, NULL, cu);
+         handle_struct_member_die (child_die, type, &fi, &template_args, cu);
 
-             if (arg != NULL)
-               template_args.push_back (arg);
-           }
+         if (is_variant_part && discr_offset == child_die->sect_off)
+           fi.fields.back ().variant.is_discriminant = true;
 
          child_die = sibling_die (child_die);
        }
@@ -16064,7 +16432,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
       /* Attach fields and member functions to the type.  */
       if (fi.nfields)
        dwarf2_attach_fields_to_type (&fi, type, cu);
-      if (fi.nfnfields)
+      if (!fi.fnfieldlists.empty ())
        {
          dwarf2_attach_fn_fields_to_type (&fi, type, cu);
 
@@ -16134,56 +16502,41 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
 
       /* Copy fi.typedef_field_list linked list elements content into the
         allocated array TYPE_TYPEDEF_FIELD_ARRAY (type).  */
-      if (fi.typedef_field_list)
+      if (!fi.typedef_field_list.empty ())
        {
-         int i = fi.typedef_field_list_count;
+         int count = fi.typedef_field_list.size ();
 
          ALLOCATE_CPLUS_STRUCT_TYPE (type);
          TYPE_TYPEDEF_FIELD_ARRAY (type)
            = ((struct decl_field *)
-              TYPE_ALLOC (type, sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * i));
-         TYPE_TYPEDEF_FIELD_COUNT (type) = i;
-
-         /* Reverse the list order to keep the debug info elements order.  */
-         while (--i >= 0)
-           {
-             struct decl_field *dest, *src;
+              TYPE_ALLOC (type,
+                          sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * count));
+         TYPE_TYPEDEF_FIELD_COUNT (type) = count;
 
-             dest = &TYPE_TYPEDEF_FIELD (type, i);
-             src = &fi.typedef_field_list->field;
-             fi.typedef_field_list = fi.typedef_field_list->next;
-             *dest = *src;
-           }
+         for (int i = 0; i < fi.typedef_field_list.size (); ++i)
+           TYPE_TYPEDEF_FIELD (type, i) = fi.typedef_field_list[i];
        }
 
       /* Copy fi.nested_types_list linked list elements content into the
         allocated array TYPE_NESTED_TYPES_ARRAY (type).  */
-      if (fi.nested_types_list != NULL && cu->language != language_ada)
+      if (!fi.nested_types_list.empty () && cu->language != language_ada)
        {
-         int i = fi.nested_types_list_count;
+         int count = fi.nested_types_list.size ();
 
          ALLOCATE_CPLUS_STRUCT_TYPE (type);
          TYPE_NESTED_TYPES_ARRAY (type)
            = ((struct decl_field *)
-              TYPE_ALLOC (type, sizeof (struct decl_field) * i));
-         TYPE_NESTED_TYPES_COUNT (type) = i;
-
-         /* Reverse the list order to keep the debug info elements order.  */
-         while (--i >= 0)
-           {
-             struct decl_field *dest, *src;
+              TYPE_ALLOC (type, sizeof (struct decl_field) * count));
+         TYPE_NESTED_TYPES_COUNT (type) = count;
 
-             dest = &TYPE_NESTED_TYPES_FIELD (type, i);
-             src = &fi.nested_types_list->field;
-             fi.nested_types_list = fi.nested_types_list->next;
-             *dest = *src;
-           }
+         for (int i = 0; i < fi.nested_types_list.size (); ++i)
+           TYPE_NESTED_TYPES_FIELD (type, i) = fi.nested_types_list[i];
        }
-
-      do_cleanups (back_to);
     }
 
   quirk_gcc_member_function_pointer (type, objfile);
+  if (cu->language == language_rust && die->tag == DW_TAG_union_type)
+    cu->rust_unions.push_back (type);
 
   /* NOTE: carlton/2004-03-16: GCC 3.4 (or at least one of its
      snapshots) has been known to create a die giving a declaration