#include "objfiles.h"
#include "psymtab.h"
#include "rust-lang.h"
+#include "typeprint.h"
#include "valprint.h"
#include "varobj.h"
+#include <algorithm>
#include <string>
#include <vector>
&& TYPE_FLAG_DISCRIMINATED_UNION (TYPE_FIELD_TYPE (type, 0)));
}
+/* Return true if TYPE, which must be an enum type, has no
+ variants. */
+
+static bool
+rust_empty_enum_p (const struct type *type)
+{
+ gdb_assert (rust_enum_p (type));
+ /* In Rust the enum always fills the containing structure. */
+ gdb_assert (TYPE_FIELD_BITPOS (type, 0) == 0);
+
+ return TYPE_NFIELDS (TYPE_FIELD_TYPE (type, 0)) == 0;
+}
+
/* Given an enum type and contents, find which variant is active. */
-struct field *
+static struct field *
rust_enum_variant (struct type *type, const gdb_byte *contents)
{
/* In Rust the enum always fills the containing structure. */
opts.deref_ref = 0;
+ if (rust_empty_enum_p (type))
+ {
+ /* Print the enum type name here to be more clear. */
+ fprintf_filtered (stream, _("%s {<No data fields>}"), TYPE_NAME (type));
+ return;
+ }
+
const gdb_byte *valaddr = value_contents_for_printing (val);
struct field *variant_field = rust_enum_variant (type, valaddr);
embedded_offset += FIELD_BITPOS (*variant_field) / 8;
rust_internal_print_type (struct type *type, const char *varstring,
struct ui_file *stream, int show, int level,
const struct type_print_options *flags,
- bool for_rust_enum);
+ bool for_rust_enum, print_offset_data *podata);
/* Print a struct or union typedef. */
static void
rust_print_struct_def (struct type *type, const char *varstring,
struct ui_file *stream, int show, int level,
const struct type_print_options *flags,
- bool for_rust_enum)
+ bool for_rust_enum, print_offset_data *podata)
{
/* Print a tuple type simply. */
if (rust_tuple_type_p (type))
if (TYPE_N_BASECLASSES (type) > 0)
c_print_type (type, varstring, stream, show, level, flags);
+ if (flags->print_offsets)
+ {
+ /* Temporarily bump the level so that the output lines up
+ correctly. */
+ level += 2;
+ }
+
/* Compute properties of TYPE here because, in the enum case, the
rest of the code ends up looking only at the variant part. */
const char *tagname = TYPE_NAME (type);
if (is_enum)
{
fputs_filtered ("enum ", stream);
+
+ if (rust_empty_enum_p (type))
+ {
+ if (tagname != NULL)
+ {
+ fputs_filtered (tagname, stream);
+ fputs_filtered (" ", stream);
+ }
+ fputs_filtered ("{}", stream);
+ return;
+ }
+
type = TYPE_FIELD_TYPE (type, 0);
struct dynamic_prop *discriminant_prop
if (TYPE_NFIELDS (type) == 0 && !is_tuple)
return;
- if (for_rust_enum)
+ if (for_rust_enum && !flags->print_offsets)
fputs_filtered (is_tuple_struct ? "(" : "{", stream);
else
fputs_filtered (is_tuple_struct ? " (\n" : " {\n", stream);
+ /* When printing offsets, we rearrange the fields into storage
+ order. This lets us show holes more clearly. We work using
+ field indices here because it simplifies calls to
+ print_offset_data::update below. */
+ std::vector<int> fields;
for (int i = 0; i < TYPE_NFIELDS (type); ++i)
{
- QUIT;
if (field_is_static (&TYPE_FIELD (type, i)))
continue;
+ if (is_enum && i == enum_discriminant_index)
+ continue;
+ fields.push_back (i);
+ }
+ if (flags->print_offsets)
+ std::sort (fields.begin (), fields.end (),
+ [&] (int a, int b)
+ {
+ return (TYPE_FIELD_BITPOS (type, a)
+ < TYPE_FIELD_BITPOS (type, b));
+ });
+
+ for (int i : fields)
+ {
+ QUIT;
+
+ gdb_assert (!field_is_static (&TYPE_FIELD (type, i)));
+ gdb_assert (! (is_enum && i == enum_discriminant_index));
+
+ if (flags->print_offsets)
+ podata->update (type, i, stream);
/* We'd like to print "pub" here as needed, but rustc
doesn't emit the debuginfo, and our types don't have
/* For a tuple struct we print the type but nothing
else. */
- if (!for_rust_enum)
+ if (!for_rust_enum || flags->print_offsets)
print_spaces_filtered (level + 2, stream);
if (is_enum)
- {
- if (i == enum_discriminant_index)
- continue;
- fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
- }
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
else if (!is_tuple_struct)
fprintf_filtered (stream, "%s: ", TYPE_FIELD_NAME (type, i));
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), NULL,
stream, (is_enum ? show : show - 1),
- level + 2, flags, is_enum);
- if (!for_rust_enum)
+ level + 2, flags, is_enum, podata);
+ if (!for_rust_enum || flags->print_offsets)
fputs_filtered (",\n", stream);
+ /* Note that this check of "I" is ok because we only sorted the
+ fields by offset when print_offsets was set, so we won't take
+ this branch in that case. */
else if (i + 1 < TYPE_NFIELDS (type))
fputs_filtered (", ", stream);
}
- if (!for_rust_enum)
+ if (flags->print_offsets)
+ {
+ /* Undo the temporary level increase we did above. */
+ level -= 2;
+ podata->finish (type, level, stream);
+ print_spaces_filtered (print_offset_data::indentation, stream);
+ if (level == 0)
+ print_spaces_filtered (2, stream);
+ }
+ if (!for_rust_enum || flags->print_offsets)
print_spaces_filtered (level, stream);
fputs_filtered (is_tuple_struct ? ")" : "}", stream);
}
rust_internal_print_type (struct type *type, const char *varstring,
struct ui_file *stream, int show, int level,
const struct type_print_options *flags,
- bool for_rust_enum)
+ bool for_rust_enum, print_offset_data *podata)
{
- int i;
-
QUIT;
if (show <= 0
&& TYPE_NAME (type) != NULL)
if (varstring != NULL)
fputs_filtered (varstring, stream);
fputs_filtered ("(", stream);
- for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
{
QUIT;
if (i > 0)
fputs_filtered (", ", stream);
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), "", stream,
- -1, 0, flags, false);
+ -1, 0, flags, false, podata);
}
fputs_filtered (")", stream);
/* If it returns unit, we can omit the return type. */
{
fputs_filtered (" -> ", stream);
rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream,
- -1, 0, flags, false);
+ -1, 0, flags, false, podata);
}
break;
fputs_filtered ("[", stream);
rust_internal_print_type (TYPE_TARGET_TYPE (type), NULL,
- stream, show - 1, level, flags, false);
+ stream, show - 1, level, flags, false,
+ podata);
if (TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCEXPR
|| TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCLIST)
case TYPE_CODE_UNION:
case TYPE_CODE_STRUCT:
rust_print_struct_def (type, varstring, stream, show, level, flags,
- for_rust_enum);
+ for_rust_enum, podata);
break;
case TYPE_CODE_ENUM:
{
- int i, len = 0;
+ int len = 0;
fputs_filtered ("enum ", stream);
if (TYPE_NAME (type) != NULL)
}
fputs_filtered ("{\n", stream);
- for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
{
const char *name = TYPE_FIELD_NAME (type, i);
struct ui_file *stream, int show, int level,
const struct type_print_options *flags)
{
+ print_offset_data podata;
rust_internal_print_type (type, varstring, stream, show, level,
- flags, false);
+ flags, false, &podata);
}
\f
case OP_RUST_ARRAY:
{
- int pc = (*pos)++;
+ (*pos)++;
int copies;
struct value *elt;
struct value *ncopies;
/* Anonymous field access, i.e. foo.1. */
struct value *lhs;
int pc, field_number, nfields;
- struct type *type, *variant_type;
+ struct type *type;
pc = (*pos)++;
field_number = longest_to_int (exp->elts[pc + 1].longconst);
if (rust_enum_p (type))
{
+ if (rust_empty_enum_p (type))
+ error (_("Cannot access field %d of empty enum %s"),
+ field_number, TYPE_NAME (type));
+
const gdb_byte *valaddr = value_contents (lhs);
struct field *variant_field = rust_enum_variant (type, valaddr);
type = value_type (lhs);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT && rust_enum_p (type))
{
+ if (rust_empty_enum_p (type))
+ error (_("Cannot access field %s of empty enum %s"),
+ field_name, TYPE_NAME (type));
+
const gdb_byte *valaddr = value_contents (lhs);
struct field *variant_field = rust_enum_variant (type, valaddr);
struct type *outer_type = type;
type = value_type (lhs);
if (rust_tuple_type_p (type) || rust_tuple_struct_type_p (type))
- error (_("Attempting to access named field foo of tuple "
+ error (_("Attempting to access named field %s of tuple "
"variant %s::%s, which has only anonymous fields"),
- TYPE_NAME (outer_type),
+ field_name, TYPE_NAME (outer_type),
rust_last_path_segment (TYPE_NAME (type)));
TRY
rust_extensions,
&exp_descriptor_rust,
rust_parse,
- rustyyerror,
null_post_parser,
rust_printchar, /* Print a character constant */
rust_printstr, /* Function to print string constant */