+/* Print a single variant part, PART, on STREAM. TYPE is the
+ enclosing type. SHOW, LEVEL, and FLAGS are the usual type-printing
+ settings. This prints information about PART and the fields it
+ controls. It returns the index of the next field that should be
+ shown -- that is, one after the last field printed by this
+ call. */
+
+static int
+print_variant_part (const variant_part &part,
+ struct type *type, struct ui_file *stream,
+ int show, int level,
+ const struct type_print_options *flags)
+{
+ struct type *discr_type = nullptr;
+ const char *name;
+ if (part.discriminant_index == -1)
+ name = "?";
+ else
+ {
+ name = TYPE_FIELD_NAME (type, part.discriminant_index);
+ discr_type = TYPE_FIELD_TYPE (type, part.discriminant_index);
+ }
+
+ fprintf_filtered (stream, "\n%*scase %s is", level + 4, "", name);
+
+ int last_field = -1;
+ for (const variant &variant : part.variants)
+ {
+ print_choices (discr_type, variant, stream, level + 8);
+
+ if (variant.first_field == variant.last_field)
+ fprintf_filtered (stream, " null;");
+ else
+ {
+ print_record_field_types_dynamic (variant.parts,
+ variant.first_field,
+ variant.last_field, type, stream,
+ show, level + 8, flags);
+ last_field = variant.last_field;
+ }
+ }
+
+ fprintf_filtered (stream, "\n%*send case;", level + 4, "");
+
+ return last_field;
+}
+
+/* Print some fields of TYPE to STREAM. SHOW, LEVEL, and FLAGS are
+ the usual type-printing settings. PARTS is the array of variant
+ parts that correspond to the range of fields to be printed. FROM
+ and TO are the range of fields to print. */
+
+static void
+print_record_field_types_dynamic (const gdb::array_view<variant_part> &parts,
+ int from, int to,
+ struct type *type, struct ui_file *stream,
+ int show, int level,
+ const struct type_print_options *flags)
+{
+ int field = from;
+
+ for (const variant_part &part : parts)
+ {
+ if (part.variants.empty ())
+ continue;
+
+ /* Print any non-varying fields. */
+ int first_varying = part.variants[0].first_field;
+ print_selected_record_field_types (type, type, field,
+ first_varying - 1, stream,
+ show, level, flags);
+
+ field = print_variant_part (part, type, stream, show, level, flags);
+ }
+
+ /* Print any trailing fields that we were asked to print. */
+ print_selected_record_field_types (type, type, field, to - 1, stream, show,
+ level, flags);
+}
+
+/* Print a description on STREAM of all fields of record or union type
+ TYPE, as for print_selected_record_field_types, above. */
+
+static int
+print_record_field_types (struct type *type, struct type *outer_type,
+ struct ui_file *stream, int show, int level,
+ const struct type_print_options *flags)
+{
+ struct dynamic_prop *prop = type->dyn_prop (DYN_PROP_VARIANT_PARTS);
+ if (prop != nullptr)
+ {
+ if (prop->kind == PROP_TYPE)
+ {
+ type = prop->data.original_type;
+ prop = type->dyn_prop (DYN_PROP_VARIANT_PARTS);
+ }
+ gdb_assert (prop->kind == PROP_VARIANT_PARTS);
+ print_record_field_types_dynamic (*prop->data.variant_parts,
+ 0, type->num_fields (),
+ type, stream, show, level, flags);
+ return type->num_fields ();
+ }
+
+ return print_selected_record_field_types (type, outer_type,
+ 0, type->num_fields () - 1,
+ stream, show, level, flags);
+}
+
+
+/* Print record type TYPE on STREAM. LEVEL is the recursion (indentation)
+ level, in case the element type itself has nested structure, and SHOW is
+ the number of levels of internal structure to show (see ada_print_type). */
+
+static void
+print_record_type (struct type *type0, struct ui_file *stream, int show,
+ int level, const struct type_print_options *flags)
+{
+ struct type *parent_type;
+ struct type *type;
+
+ type = ada_find_parallel_type (type0, "___XVE");
+ if (type == NULL)
+ type = type0;
+
+ parent_type = ada_parent_type (type);
+ if (ada_type_name (parent_type) != NULL)
+ {
+ const char *parent_name = decoded_type_name (parent_type);
+
+ /* If we fail to decode the parent type name, then use the parent
+ type name as is. Not pretty, but should never happen except
+ when the debugging info is incomplete or incorrect. This
+ prevents a crash trying to print a NULL pointer. */
+ if (parent_name == NULL)
+ parent_name = ada_type_name (parent_type);
+ fprintf_filtered (stream, "new %s with record", parent_name);
+ }
+ else if (parent_type == NULL && ada_is_tagged_type (type, 0))
+ fprintf_filtered (stream, "tagged record");
+ else
+ fprintf_filtered (stream, "record");