/* Rust language support routines for GDB, the GNU debugger.
- Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ Copyright (C) 2016-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbarch.h"
#include "infcall.h"
#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>
+#include "cli/cli-style.h"
-extern initialize_file_ftype _initialize_rust_language;
-
-/* Returns the last segment of a Rust path like foo::bar::baz. Will
- not handle cases where the last segment contains generics. This
- will return NULL if the last segment cannot be found. */
+/* See rust-lang.h. */
-static const char *
-rust_last_path_segment (const char * path)
+const char *
+rust_last_path_segment (const char *path)
{
const char *result = strrchr (path, ':');
if (result == NULL)
- return NULL;
+ return path;
return result + 1;
}
-/* Find the Rust crate for BLOCK. If no crate can be found, returns
- NULL. Otherwise, returns a newly allocated string that the caller
- is responsible for freeing. */
+/* See rust-lang.h. */
-char *
+std::string
rust_crate_for_block (const struct block *block)
{
const char *scope = block_scope (block);
if (scope[0] == '\0')
- return NULL;
+ return std::string ();
- return xstrndup (scope, cp_find_first_component (scope));
+ return std::string (scope, cp_find_first_component (scope));
}
-/* Information about the discriminant/variant of an enum */
-
-struct disr_info
-{
- /* Name of field. */
- std::string name;
- /* Field number in union. Negative on error. For an encoded enum,
- the "hidden" member will always be field 1, and the "real" member
- will always be field 0. */
- int field_no;
- /* True if this is an encoded enum that has a single "real" member
- and a single "hidden" member. */
- unsigned int is_encoded : 1;
-};
-
-/* The prefix of a specially-encoded enum. */
-
-#define RUST_ENUM_PREFIX "RUST$ENCODED$ENUM$"
+/* Return true if TYPE, which must be a struct type, represents a Rust
+ enum. */
-/* The number of the real field. */
-
-#define RUST_ENCODED_ENUM_REAL 0
-
-/* The number of the hidden field. */
-
-#define RUST_ENCODED_ENUM_HIDDEN 1
-
-/* Whether or not a TYPE_CODE_UNION value is an untagged union
- as opposed to being a regular Rust enum. */
static bool
-rust_union_is_untagged (struct type *type)
+rust_enum_p (const struct type *type)
{
- /* Unions must have at least one field. */
- if (TYPE_NFIELDS (type) == 0)
- return false;
- /* If the first field is named, but the name has the rust enum prefix,
- it is an enum. */
- if (strncmp (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX,
- strlen (RUST_ENUM_PREFIX)) == 0)
- return false;
- /* Unions only have named fields. */
- for (int i = 0; i < TYPE_NFIELDS (type); ++i)
- {
- if (strlen (TYPE_FIELD_NAME (type, i)) == 0)
- return false;
- }
- return true;
+ return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1
+ && TYPE_FLAG_DISCRIMINATED_UNION (TYPE_FIELD_TYPE (type, 0)));
}
-/* Utility function to get discriminant info for a given value. */
+/* Return true if TYPE, which must be an enum type, has no
+ variants. */
-static struct disr_info
-rust_get_disr_info (struct type *type, const gdb_byte *valaddr,
- int embedded_offset, CORE_ADDR address,
- struct value *val)
+static bool
+rust_empty_enum_p (const struct type *type)
{
- int i;
- struct disr_info ret;
- struct type *disr_type;
- struct ui_file *temp_file;
- struct value_print_options opts;
- struct cleanup *cleanup;
- const char *name_segment;
-
- get_no_prettyformat_print_options (&opts);
-
- ret.field_no = -1;
- ret.is_encoded = 0;
-
- if (TYPE_NFIELDS (type) == 0)
- error (_("Encountered void enum value"));
-
- /* If an enum has two values where one is empty and the other holds
- a pointer that cannot be zero; then the Rust compiler optimizes
- away the discriminant and instead uses a zero value in the
- pointer field to indicate the empty variant. */
- if (strncmp (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX,
- strlen (RUST_ENUM_PREFIX)) == 0)
- {
- char *tail, *token, *saveptr = NULL;
- unsigned long fieldno;
- struct type *member_type;
- LONGEST value;
-
- ret.is_encoded = 1;
-
- if (TYPE_NFIELDS (type) != 1)
- error (_("Only expected one field in %s type"), RUST_ENUM_PREFIX);
-
- /* Optimized enums have only one field. */
- member_type = TYPE_FIELD_TYPE (type, 0);
-
- gdb::unique_xmalloc_ptr<char> name (xstrdup (TYPE_FIELD_NAME (type, 0)));
- tail = name.get () + strlen (RUST_ENUM_PREFIX);
-
- /* The location of the value that doubles as a discriminant is
- stored in the name of the field, as
- 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. */
- for (token = strtok_r (tail, "$", &saveptr);
- token != NULL;
- token = strtok_r (NULL, "$", &saveptr))
- {
- if (sscanf (token, "%lu", &fieldno) != 1)
- {
- /* We have reached the enum name, which cannot start
- with a digit. */
- break;
- }
- if (fieldno >= TYPE_NFIELDS (member_type))
- error (_("%s refers to field after end of member type"),
- RUST_ENUM_PREFIX);
-
- embedded_offset += TYPE_FIELD_BITPOS (member_type, fieldno) / 8;
- member_type = TYPE_FIELD_TYPE (member_type, fieldno);
- }
-
- if (token == NULL)
- error (_("Invalid form for %s"), RUST_ENUM_PREFIX);
- value = unpack_long (member_type, valaddr + embedded_offset);
-
- if (value == 0)
- {
- ret.field_no = RUST_ENCODED_ENUM_HIDDEN;
- ret.name = std::string (TYPE_NAME (type)) + "::" + token;
- }
- else
- {
- ret.field_no = RUST_ENCODED_ENUM_REAL;
- ret.name = (std::string (TYPE_NAME (type)) + "::"
- + rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (type, 0))));
- }
-
- return ret;
- }
+ gdb_assert (rust_enum_p (type));
+ /* In Rust the enum always fills the containing structure. */
+ gdb_assert (TYPE_FIELD_BITPOS (type, 0) == 0);
- disr_type = TYPE_FIELD_TYPE (type, 0);
+ return TYPE_NFIELDS (TYPE_FIELD_TYPE (type, 0)) == 0;
+}
- if (TYPE_NFIELDS (disr_type) == 0)
- {
- /* This is a bounds check and should never be hit unless Rust
- has changed its debuginfo format. */
- error (_("Could not find enum discriminant field"));
- }
- else if (TYPE_NFIELDS (type) == 1)
- {
- /* Sometimes univariant enums are encoded without a
- discriminant. In that case, treating it as an encoded enum
- with the first field being the actual type works. */
- const char *field_name = TYPE_NAME (TYPE_FIELD_TYPE (type, 0));
- const char *last = rust_last_path_segment (field_name);
- ret.name = std::string (TYPE_NAME (type)) + "::" + last;
- ret.field_no = RUST_ENCODED_ENUM_REAL;
- ret.is_encoded = 1;
- return ret;
- }
+/* Given an enum type and contents, find which variant is active. */
- if (strcmp (TYPE_FIELD_NAME (disr_type, 0), "RUST$ENUM$DISR") != 0)
- error (_("Rust debug format has changed"));
-
- temp_file = mem_fileopen ();
- cleanup = make_cleanup_ui_file_delete (temp_file);
- /* The first value of the first field (or any field)
- is the discriminant value. */
- c_val_print (TYPE_FIELD_TYPE (disr_type, 0),
- (embedded_offset + TYPE_FIELD_BITPOS (type, 0) / 8
- + TYPE_FIELD_BITPOS (disr_type, 0) / 8),
- address, temp_file,
- 0, val, &opts);
-
- ret.name = ui_file_as_string (temp_file);
- name_segment = rust_last_path_segment (ret.name.c_str ());
- if (name_segment != NULL)
- {
- for (i = 0; i < TYPE_NFIELDS (type); ++i)
- {
- /* Sadly, the discriminant value paths do not match the type
- field name paths ('core::option::Option::Some' vs
- 'core::option::Some'). However, enum variant names are
- unique in the last path segment and the generics are not
- part of this path, so we can just compare those. This is
- hackish and would be better fixed by improving rustc's
- metadata for enums. */
- const char *field_type = TYPE_NAME (TYPE_FIELD_TYPE (type, i));
-
- if (field_type != NULL
- && strcmp (name_segment,
- rust_last_path_segment (field_type)) == 0)
- {
- ret.field_no = i;
- break;
- }
- }
- }
+static struct field *
+rust_enum_variant (struct type *type, const gdb_byte *contents)
+{
+ /* In Rust the enum always fills the containing structure. */
+ gdb_assert (TYPE_FIELD_BITPOS (type, 0) == 0);
- if (ret.field_no == -1 && !ret.name.empty ())
- {
- /* Somehow the discriminant wasn't found. */
- error (_("Could not find variant of %s with discriminant %s"),
- TYPE_TAG_NAME (type), ret.name.c_str ());
- }
+ struct type *union_type = TYPE_FIELD_TYPE (type, 0);
- do_cleanups (cleanup);
- return ret;
+ int fieldno = value_union_variant (union_type, contents);
+ return &TYPE_FIELD (union_type, fieldno);
}
/* See rust-lang.h. */
-int
+bool
rust_tuple_type_p (struct type *type)
{
/* The current implementation is a bit of a hack, but there's
nothing else in the debuginfo to distinguish a tuple from a
struct. */
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
- && TYPE_TAG_NAME (type) != NULL
- && TYPE_TAG_NAME (type)[0] == '(');
+ && TYPE_NAME (type) != NULL
+ && TYPE_NAME (type)[0] == '(');
}
-
/* Return true if all non-static fields of a structlike type are in a
- sequence like __0, __1, __2. OFFSET lets us skip fields. */
+ sequence like __0, __1, __2. */
-static int
-rust_underscore_fields (struct type *type, int offset)
+static bool
+rust_underscore_fields (struct type *type)
{
int i, field_number;
field_number = 0;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
- return 0;
+ return false;
for (i = 0; i < TYPE_NFIELDS (type); ++i)
{
if (!field_is_static (&TYPE_FIELD (type, i)))
{
- if (offset > 0)
- offset--;
- else
- {
- char buf[20];
+ char buf[20];
- xsnprintf (buf, sizeof (buf), "__%d", field_number);
- if (strcmp (buf, TYPE_FIELD_NAME (type, i)) != 0)
- return 0;
- field_number++;
- }
+ xsnprintf (buf, sizeof (buf), "__%d", field_number);
+ if (strcmp (buf, TYPE_FIELD_NAME (type, i)) != 0)
+ return false;
+ field_number++;
}
}
- return 1;
+ return true;
}
/* See rust-lang.h. */
-int
+bool
rust_tuple_struct_type_p (struct type *type)
{
/* This is just an approximation until DWARF can represent Rust more
precisely. We exclude zero-length structs because they may not
be tuple structs, and there's no way to tell. */
- return TYPE_NFIELDS (type) > 0 && rust_underscore_fields (type, 0);
-}
-
-/* Return true if a variant TYPE is a tuple variant, false otherwise. */
-
-static int
-rust_tuple_variant_type_p (struct type *type)
-{
- /* First field is discriminant */
- return rust_underscore_fields (type, 1);
+ return TYPE_NFIELDS (type) > 0 && rust_underscore_fields (type);
}
/* Return true if TYPE is a slice type, otherwise false. */
-static int
+static bool
rust_slice_type_p (struct type *type)
{
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
- && TYPE_TAG_NAME (type) != NULL
- && strncmp (TYPE_TAG_NAME (type), "&[", 2) == 0);
+ && TYPE_NAME (type) != NULL
+ && (strncmp (TYPE_NAME (type), "&[", 2) == 0
+ || strcmp (TYPE_NAME (type), "&str") == 0));
}
/* Return true if TYPE is a range type, otherwise false. */
-static int
+static bool
rust_range_type_p (struct type *type)
{
int i;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|| TYPE_NFIELDS (type) > 2
- || TYPE_TAG_NAME (type) == NULL
- || strstr (TYPE_TAG_NAME (type), "::Range") == NULL)
- return 0;
+ || TYPE_NAME (type) == NULL
+ || strstr (TYPE_NAME (type), "::Range") == NULL)
+ return false;
if (TYPE_NFIELDS (type) == 0)
- return 1;
+ return true;
i = 0;
if (strcmp (TYPE_FIELD_NAME (type, 0), "start") == 0)
{
if (TYPE_NFIELDS (type) == 1)
- return 1;
+ return true;
i = 1;
}
else if (TYPE_NFIELDS (type) == 2)
{
/* First field had to be "start". */
- return 0;
+ return false;
}
return strcmp (TYPE_FIELD_NAME (type, i), "end") == 0;
}
+/* Return true if TYPE is an inclusive range type, otherwise false.
+ This is only valid for types which are already known to be range
+ types. */
+
+static bool
+rust_inclusive_range_type_p (struct type *type)
+{
+ return (strstr (TYPE_NAME (type), "::RangeInclusive") != NULL
+ || strstr (TYPE_NAME (type), "::RangeToInclusive") != NULL);
+}
+
/* Return true if TYPE seems to be the type "u8", otherwise false. */
-static int
+static bool
rust_u8_type_p (struct type *type)
{
return (TYPE_CODE (type) == TYPE_CODE_INT
/* Return true if TYPE is a Rust character type. */
-static int
+static bool
rust_chartype_p (struct type *type)
{
return (TYPE_CODE (type) == TYPE_CODE_CHAR
&& TYPE_UNSIGNED (type));
}
+/* Return true if TYPE is a string type. */
+
+static bool
+rust_is_string_type_p (struct type *type)
+{
+ LONGEST low_bound, high_bound;
+
+ type = check_typedef (type);
+ return ((TYPE_CODE (type) == TYPE_CODE_STRING)
+ || (TYPE_CODE (type) == TYPE_CODE_PTR
+ && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY
+ && rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
+ && get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
+ &high_bound)))
+ || (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && !rust_enum_p (type)
+ && rust_slice_type_p (type)
+ && strcmp (TYPE_NAME (type), "&str") == 0));
+}
+
+/* If VALUE represents a trait object pointer, return the underlying
+ pointer with the correct (i.e., runtime) type. Otherwise, return
+ NULL. */
+
+static struct value *
+rust_get_trait_object_pointer (struct value *value)
+{
+ struct type *type = check_typedef (value_type (value));
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT || TYPE_NFIELDS (type) != 2)
+ return NULL;
+
+ /* Try to be a bit resilient if the ABI changes. */
+ int vtable_field = 0;
+ for (int i = 0; i < 2; ++i)
+ {
+ if (strcmp (TYPE_FIELD_NAME (type, i), "vtable") == 0)
+ vtable_field = i;
+ else if (strcmp (TYPE_FIELD_NAME (type, i), "pointer") != 0)
+ return NULL;
+ }
+
+ CORE_ADDR vtable = value_as_address (value_field (value, vtable_field));
+ struct symbol *symbol = find_symbol_at_address (vtable);
+ if (symbol == NULL || symbol->subclass != SYMBOL_RUST_VTABLE)
+ return NULL;
+
+ struct rust_vtable_symbol *vtable_sym
+ = static_cast<struct rust_vtable_symbol *> (symbol);
+ struct type *pointer_type = lookup_pointer_type (vtable_sym->concrete_type);
+ return value_cast (pointer_type, value_field (value, 1 - vtable_field));
+}
+
\f
/* la_emitchar implementation for Rust. */
\f
-/* rust_print_type branch for structs and untagged unions. */
+/* Helper function to print a string slice. */
+
+static void
+rust_val_print_str (struct ui_file *stream, struct value *val,
+ const struct value_print_options *options)
+{
+ struct value *base = value_struct_elt (&val, NULL, "data_ptr", NULL,
+ "slice");
+ struct value *len = value_struct_elt (&val, NULL, "length", NULL, "slice");
+
+ val_print_string (TYPE_TARGET_TYPE (value_type (base)), "UTF-8",
+ value_as_address (base), value_as_long (len), stream,
+ options);
+}
+
+/* rust_val_print helper for structs and untagged unions. */
static void
val_print_struct (struct type *type, int embedded_offset,
{
int i;
int first_field;
- int is_tuple = rust_tuple_type_p (type);
- int is_tuple_struct = !is_tuple && rust_tuple_struct_type_p (type);
+
+ if (rust_slice_type_p (type) && strcmp (TYPE_NAME (type), "&str") == 0)
+ {
+ /* If what we are printing here is actually a string within a
+ structure then VAL will be the original parent value, while TYPE
+ will be the type of the structure representing the string we want
+ to print.
+ However, RUST_VAL_PRINT_STR looks up the fields of the string
+ inside VAL, assuming that VAL is the string.
+ So, recreate VAL as a value representing just the string. */
+ val = value_at_lazy (type, value_address (val) + embedded_offset);
+ rust_val_print_str (stream, val, options);
+ return;
+ }
+
+ bool is_tuple = rust_tuple_type_p (type);
+ bool is_tuple_struct = !is_tuple && rust_tuple_struct_type_p (type);
struct value_print_options opts;
if (!is_tuple)
{
- if (TYPE_TAG_NAME (type) != NULL)
- fprintf_filtered (stream, "%s", TYPE_TAG_NAME (type));
+ if (TYPE_NAME (type) != NULL)
+ fprintf_filtered (stream, "%s", TYPE_NAME (type));
if (TYPE_NFIELDS (type) == 0)
return;
- if (TYPE_TAG_NAME (type) != NULL)
+ if (TYPE_NAME (type) != NULL)
fputs_filtered (" ", stream);
}
if (options->prettyformat)
{
- fputs_filtered ("\n", stream);
- print_spaces_filtered (2 + 2 * recurse, stream);
+ fputs_filtered ("\n", stream);
+ print_spaces_filtered (2 + 2 * recurse, stream);
}
else if (!first_field)
fputs_filtered (" ", stream);
if (!is_tuple && !is_tuple_struct)
{
- fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
- fputs_filtered (": ", stream);
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ fputs_filtered (": ", stream);
}
val_print (TYPE_FIELD_TYPE (type, i),
- embedded_offset + TYPE_FIELD_BITPOS (type, i) / 8,
- address,
- stream, recurse + 1, val, &opts,
- current_language);
+ embedded_offset + TYPE_FIELD_BITPOS (type, i) / 8,
+ address,
+ stream, recurse + 1, val, &opts,
+ current_language);
}
if (options->prettyformat)
fputs_filtered ("}", stream);
}
+/* rust_val_print helper for discriminated unions (Rust enums). */
+
+static void
+rust_print_enum (struct type *type, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream,
+ int recurse, struct value *val,
+ const struct value_print_options *options)
+{
+ struct value_print_options opts = *options;
+
+ opts.deref_ref = 0;
+
+ if (rust_empty_enum_p (type))
+ {
+ /* Print the enum type name here to be more clear. */
+ fprintf_filtered (stream, _("%s {%p[<No data fields>%p]}"),
+ TYPE_NAME (type),
+ metadata_style.style ().ptr (), nullptr);
+ 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;
+ struct type *variant_type = FIELD_TYPE (*variant_field);
+
+ int nfields = TYPE_NFIELDS (variant_type);
+
+ bool is_tuple = rust_tuple_struct_type_p (variant_type);
+
+ fprintf_filtered (stream, "%s", TYPE_NAME (variant_type));
+ if (nfields == 0)
+ {
+ /* In case of a nullary variant like 'None', just output
+ the name. */
+ return;
+ }
+
+ /* In case of a non-nullary variant, we output 'Foo(x,y,z)'. */
+ if (is_tuple)
+ fprintf_filtered (stream, "(");
+ else
+ {
+ /* struct variant. */
+ fprintf_filtered (stream, "{");
+ }
+
+ bool first_field = true;
+ for (int j = 0; j < TYPE_NFIELDS (variant_type); j++)
+ {
+ if (!first_field)
+ fputs_filtered (", ", stream);
+ first_field = false;
+
+ if (!is_tuple)
+ fprintf_filtered (stream, "%s: ",
+ TYPE_FIELD_NAME (variant_type, j));
+
+ val_print (TYPE_FIELD_TYPE (variant_type, j),
+ (embedded_offset
+ + TYPE_FIELD_BITPOS (variant_type, j) / 8),
+ address,
+ stream, recurse + 1, val, &opts,
+ current_language);
+ }
+
+ if (is_tuple)
+ fputs_filtered (")", stream);
+ else
+ fputs_filtered ("}", stream);
+}
+
static const struct generic_val_print_decorations rust_decorations =
{
/* Complex isn't used in Rust, but we provide C-ish values just in
break;
case TYPE_CODE_UNION:
- {
- int j, nfields, first_field, is_tuple, start;
- struct type *variant_type;
- struct disr_info disr;
- struct value_print_options opts;
-
- /* Untagged unions are printed as if they are structs.
- Since the field bit positions overlap in the debuginfo,
- the code for printing a union is same as that for a struct,
- the only difference is that the input type will have overlapping
- fields. */
- if (rust_union_is_untagged (type))
- {
+ /* Untagged unions are printed as if they are structs. Since
+ the field bit positions overlap in the debuginfo, the code
+ for printing a union is same as that for a struct, the only
+ difference is that the input type will have overlapping
+ fields. */
val_print_struct (type, embedded_offset, address, stream,
- recurse, val, options);
- break;
- }
-
- opts = *options;
- opts.deref_ref = 0;
-
- disr = rust_get_disr_info (type, valaddr, embedded_offset, address,
- val);
-
- if (disr.is_encoded && disr.field_no == RUST_ENCODED_ENUM_HIDDEN)
- {
- fprintf_filtered (stream, "%s", disr.name.c_str ());
- break;
- }
-
- first_field = 1;
- variant_type = TYPE_FIELD_TYPE (type, disr.field_no);
- nfields = TYPE_NFIELDS (variant_type);
-
- is_tuple = (disr.is_encoded
- ? rust_tuple_struct_type_p (variant_type)
- : rust_tuple_variant_type_p (variant_type));
- start = disr.is_encoded ? 0 : 1;
-
- if (nfields > start)
- {
- /* In case of a non-nullary variant, we output 'Foo(x,y,z)'. */
- if (is_tuple)
- fprintf_filtered (stream, "%s(", disr.name.c_str ());
- else
- {
- /* struct variant. */
- fprintf_filtered (stream, "%s{", disr.name.c_str ());
- }
- }
- else
- {
- /* In case of a nullary variant like 'None', just output
- the name. */
- fprintf_filtered (stream, "%s", disr.name.c_str ());
- break;
- }
-
- for (j = start; j < TYPE_NFIELDS (variant_type); j++)
- {
- if (!first_field)
- fputs_filtered (", ", stream);
- first_field = 0;
-
- if (!is_tuple)
- fprintf_filtered (stream, "%s: ",
- TYPE_FIELD_NAME (variant_type, j));
-
- val_print (TYPE_FIELD_TYPE (variant_type, j),
- (embedded_offset
- + TYPE_FIELD_BITPOS (type, disr.field_no) / 8
- + TYPE_FIELD_BITPOS (variant_type, j) / 8),
- address,
- stream, recurse + 1, val, &opts,
- current_language);
- }
-
- if (is_tuple)
- fputs_filtered (")", stream);
- else
- fputs_filtered ("}", stream);
- }
+ recurse, val, options);
break;
case TYPE_CODE_STRUCT:
- val_print_struct (type, embedded_offset, address, stream,
- recurse, val, options);
+ if (rust_enum_p (type))
+ rust_print_enum (type, embedded_offset, address, stream,
+ recurse, val, options);
+ else
+ val_print_struct (type, embedded_offset, address, stream,
+ recurse, val, options);
break;
default:
\f
static void
-rust_print_type (struct type *type, const char *varstring,
- struct ui_file *stream, int show, int level,
- const struct type_print_options *flags);
+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, 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)
+ struct ui_file *stream, int show, int level,
+ const struct type_print_options *flags,
+ bool for_rust_enum, print_offset_data *podata)
{
- int is_tuple_struct, i;
+ /* Print a tuple type simply. */
+ if (rust_tuple_type_p (type))
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ return;
+ }
- /* Print a tuple type simply. */
- if (rust_tuple_type_p (type))
- {
- fputs_filtered (TYPE_TAG_NAME (type), stream);
- return;
- }
+ /* If we see a base class, delegate to C. */
+ 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);
+ bool is_tuple_struct = rust_tuple_struct_type_p (type);
+ bool is_tuple = rust_tuple_type_p (type);
+ bool is_enum = rust_enum_p (type);
- /* If we see a base class, delegate to C. */
- if (TYPE_N_BASECLASSES (type) > 0)
- c_print_type (type, varstring, stream, show, level, flags);
+ int enum_discriminant_index = -1;
- /* This code path is also used by unions. */
- if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
- fputs_filtered ("struct ", stream);
+ if (for_rust_enum)
+ {
+ /* Already printing an outer enum, so nothing to print here. */
+ }
else
- fputs_filtered ("union ", stream);
+ {
+ /* This code path is also used by unions and enums. */
+ if (is_enum)
+ {
+ fputs_filtered ("enum ", stream);
- if (TYPE_TAG_NAME (type) != NULL)
- fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (rust_empty_enum_p (type))
+ {
+ if (tagname != NULL)
+ {
+ fputs_filtered (tagname, stream);
+ fputs_filtered (" ", stream);
+ }
+ fputs_filtered ("{}", stream);
+ return;
+ }
- is_tuple_struct = rust_tuple_struct_type_p (type);
+ type = TYPE_FIELD_TYPE (type, 0);
- if (TYPE_NFIELDS (type) == 0 && !rust_tuple_type_p (type))
- return;
- fputs_filtered (is_tuple_struct ? " (\n" : " {\n", stream);
+ struct dynamic_prop *discriminant_prop
+ = get_dyn_prop (DYN_PROP_DISCRIMINATED, type);
+ struct discriminant_info *info
+ = (struct discriminant_info *) discriminant_prop->data.baton;
+ enum_discriminant_index = info->discriminant_index;
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ fputs_filtered ("struct ", stream);
+ else
+ fputs_filtered ("union ", stream);
- for (i = 0; i < TYPE_NFIELDS (type); ++i)
- {
- const char *name;
+ if (tagname != NULL)
+ fputs_filtered (tagname, stream);
+ }
- QUIT;
- if (field_is_static (&TYPE_FIELD (type, i)))
- continue;
-
- /* We'd like to print "pub" here as needed, but rustc
- doesn't emit the debuginfo, and our types don't have
- cplus_struct_type attached. */
-
- /* For a tuple struct we print the type but nothing
- else. */
- print_spaces_filtered (level + 2, stream);
- if (!is_tuple_struct)
- fprintf_filtered (stream, "%s: ", TYPE_FIELD_NAME (type, i));
-
- rust_print_type (TYPE_FIELD_TYPE (type, i), NULL,
- stream, show - 1, level + 2,
- flags);
- fputs_filtered (",\n", stream);
- }
+ if (TYPE_NFIELDS (type) == 0 && !is_tuple)
+ return;
+ 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)
+ {
+ 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
+ cplus_struct_type attached. */
+
+ /* For a tuple struct we print the type but nothing
+ else. */
+ if (!for_rust_enum || flags->print_offsets)
+ print_spaces_filtered (level + 2, stream);
+ if (is_enum)
+ 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, 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);
+ }
- fprintfi_filtered (level, stream, is_tuple_struct ? ")" : "}");
+ 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);
}
/* la_print_typedef implementation for Rust. */
struct ui_file *stream)
{
type = check_typedef (type);
- fprintf_filtered (stream, "type %s = ", SYMBOL_PRINT_NAME (new_symbol));
+ fprintf_filtered (stream, "type %s = ", new_symbol->print_name ());
type_print (type, "", stream, 0);
- fprintf_filtered (stream, ";\n");
+ fprintf_filtered (stream, ";");
}
/* la_print_type implementation for Rust. */
static void
-rust_print_type (struct type *type, const char *varstring,
- struct ui_file *stream, int show, int level,
- const struct type_print_options *flags)
+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, print_offset_data *podata)
{
- int i;
-
QUIT;
if (show <= 0
&& TYPE_NAME (type) != NULL)
switch (TYPE_CODE (type))
{
case TYPE_CODE_VOID:
- fputs_filtered ("()", stream);
+ /* If we have an enum, we've already printed the type's
+ unqualified name, and there is nothing else to print
+ here. */
+ if (!for_rust_enum)
+ fputs_filtered ("()", stream);
break;
case TYPE_CODE_FUNC:
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_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0,
- flags);
+ rust_internal_print_type (TYPE_FIELD_TYPE (type, i), "", stream,
+ -1, 0, flags, false, podata);
}
fputs_filtered (")", stream);
/* If it returns unit, we can omit the return type. */
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
{
fputs_filtered (" -> ", stream);
- rust_print_type (TYPE_TARGET_TYPE (type), "", stream, -1, 0, flags);
+ rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream,
+ -1, 0, flags, false, podata);
}
break;
LONGEST low_bound, high_bound;
fputs_filtered ("[", stream);
- rust_print_type (TYPE_TARGET_TYPE (type), NULL,
- stream, show - 1, level, flags);
- fputs_filtered ("; ", stream);
+ rust_internal_print_type (TYPE_TARGET_TYPE (type), NULL,
+ 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)
- fprintf_filtered (stream, "variable length");
+ fprintf_filtered (stream, "; variable length");
else if (get_array_bounds (type, &low_bound, &high_bound))
- fprintf_filtered (stream, "%s",
+ fprintf_filtered (stream, "; %s",
plongest (high_bound - low_bound + 1));
fputs_filtered ("]", stream);
}
break;
+ case TYPE_CODE_UNION:
case TYPE_CODE_STRUCT:
- rust_print_struct_def (type, varstring, stream, show, level, flags);
+ rust_print_struct_def (type, varstring, stream, show, level, flags,
+ for_rust_enum, podata);
break;
case TYPE_CODE_ENUM:
{
- int i, len = 0;
+ int len = 0;
fputs_filtered ("enum ", stream);
- if (TYPE_TAG_NAME (type) != NULL)
+ if (TYPE_NAME (type) != NULL)
{
- fputs_filtered (TYPE_TAG_NAME (type), stream);
+ fputs_filtered (TYPE_NAME (type), stream);
fputs_filtered (" ", stream);
- len = strlen (TYPE_TAG_NAME (type));
+ len = strlen (TYPE_NAME (type));
}
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);
QUIT;
if (len > 0
- && strncmp (name, TYPE_TAG_NAME (type), len) == 0
+ && strncmp (name, TYPE_NAME (type), len) == 0
&& name[len] == ':'
&& name[len + 1] == ':')
name += len + 2;
}
break;
- case TYPE_CODE_UNION:
+ case TYPE_CODE_PTR:
{
- /* ADT enums. */
- int i, len = 0;
- /* Skip the discriminant field. */
- int skip_to = 1;
-
- /* Unions and structs have the same syntax in Rust,
- the only difference is that structs are declared with `struct`
- and union with `union`. This difference is handled in the struct
- printer. */
- if (rust_union_is_untagged (type))
- {
- rust_print_struct_def (type, varstring, stream, show, level, flags);
- break;
- }
-
- fputs_filtered ("enum ", stream);
- if (TYPE_TAG_NAME (type) != NULL)
- {
- fputs_filtered (TYPE_TAG_NAME (type), stream);
- fputs_filtered (" ", stream);
- }
- fputs_filtered ("{\n", stream);
-
- if (strncmp (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX,
- strlen (RUST_ENUM_PREFIX)) == 0)
- {
- const char *zero_field = strrchr (TYPE_FIELD_NAME (type, 0), '$');
- if (zero_field != NULL && strlen (zero_field) > 1)
- {
- fprintfi_filtered (level + 2, stream, "%s,\n", zero_field + 1);
- /* There is no explicit discriminant field, skip nothing. */
- skip_to = 0;
- }
- }
-
- for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ if (TYPE_NAME (type) != nullptr)
+ fputs_filtered (TYPE_NAME (type), stream);
+ else
{
- struct type *variant_type = TYPE_FIELD_TYPE (type, i);
- const char *name
- = rust_last_path_segment (TYPE_NAME (variant_type));
-
- fprintfi_filtered (level + 2, stream, "%s", name);
-
- if (TYPE_NFIELDS (variant_type) > skip_to)
- {
- int first = 1;
- int is_tuple = rust_tuple_variant_type_p (variant_type);
- int j;
-
- fputs_filtered (is_tuple ? "(" : "{", stream);
- for (j = skip_to; j < TYPE_NFIELDS (variant_type); j++)
- {
- if (first)
- first = 0;
- else
- fputs_filtered (", ", stream);
-
- if (!is_tuple)
- fprintf_filtered (stream, "%s: ",
- TYPE_FIELD_NAME (variant_type, j));
-
- rust_print_type (TYPE_FIELD_TYPE (variant_type, j), NULL,
- stream, show - 1, level + 2,
- flags);
- }
- fputs_filtered (is_tuple ? ")" : "}", stream);
- }
-
- fputs_filtered (",\n", stream);
+ /* We currently can't distinguish between pointers and
+ references. */
+ fputs_filtered ("*mut ", stream);
+ type_print (TYPE_TARGET_TYPE (type), "", stream, 0);
}
-
- fputs_filtered ("}", stream);
}
break;
}
}
-\f
-
-/* Compute the alignment of the type T. */
-
-static int
-rust_type_alignment (struct type *t)
+static void
+rust_print_type (struct type *type, const char *varstring,
+ struct ui_file *stream, int show, int level,
+ const struct type_print_options *flags)
{
- t = check_typedef (t);
- switch (TYPE_CODE (t))
- {
- default:
- error (_("Could not compute alignment of type"));
-
- case TYPE_CODE_PTR:
- case TYPE_CODE_ENUM:
- case TYPE_CODE_INT:
- case TYPE_CODE_FLT:
- case TYPE_CODE_REF:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_BOOL:
- return TYPE_LENGTH (t);
-
- case TYPE_CODE_ARRAY:
- case TYPE_CODE_COMPLEX:
- return rust_type_alignment (TYPE_TARGET_TYPE (t));
-
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- {
- int i;
- int align = 1;
-
- for (i = 0; i < TYPE_NFIELDS (t); ++i)
- {
- int a = rust_type_alignment (TYPE_FIELD_TYPE (t, i));
- if (a > align)
- align = a;
- }
- return align;
- }
- }
+ print_offset_data podata;
+ rust_internal_print_type (type, varstring, stream, show, level,
+ flags, false, &podata);
}
+\f
+
/* Like arch_composite_type, but uses TYPE to decide how to allocate
-- either on an obstack or on a gdbarch. */
TYPE_CODE (result) = TYPE_CODE_STRUCT;
TYPE_NAME (result) = name;
- TYPE_TAG_NAME (result) = name;
TYPE_NFIELDS (result) = nfields;
TYPE_FIELDS (result)
if (field2 != NULL)
{
struct field *field = &TYPE_FIELD (result, i);
- int align = rust_type_alignment (type2);
+ unsigned align = type_align (type2);
if (align != 0)
{
&& TYPE_CODE (type) != TYPE_CODE_ENUM)
|| rust_tuple_type_p (type))
error (_("Method calls only supported on struct or enum types"));
- if (TYPE_TAG_NAME (type) == NULL)
+ if (TYPE_NAME (type) == NULL)
error (_("Method call on nameless type"));
- std::string name = std::string (TYPE_TAG_NAME (type)) + "::" + method;
+ std::string name = std::string (TYPE_NAME (type)) + "::" + method;
block = get_selected_block (0);
sym = lookup_symbol (name.c_str (), block, VAR_DOMAIN, NULL);
if (noside == EVAL_AVOID_SIDE_EFFECTS)
result = value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
else
- result = call_function_by_hand (function, num_args + 1, args.data ());
+ result = call_function_by_hand (function, NULL, args);
return result;
}
kind = (enum range_type) longest_to_int (exp->elts[*pos + 1].longconst);
*pos += 3;
- if (kind == HIGH_BOUND_DEFAULT || kind == NONE_BOUND_DEFAULT)
+ if (kind == HIGH_BOUND_DEFAULT || kind == NONE_BOUND_DEFAULT
+ || kind == NONE_BOUND_DEFAULT_EXCLUSIVE)
low = evaluate_subexp (NULL_TYPE, exp, pos, noside);
- if (kind == LOW_BOUND_DEFAULT || kind == NONE_BOUND_DEFAULT)
+ if (kind == LOW_BOUND_DEFAULT || kind == LOW_BOUND_DEFAULT_EXCLUSIVE
+ || kind == NONE_BOUND_DEFAULT || kind == NONE_BOUND_DEFAULT_EXCLUSIVE)
high = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ bool inclusive = (kind == NONE_BOUND_DEFAULT || kind == LOW_BOUND_DEFAULT);
if (noside == EVAL_SKIP)
return value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
else
{
index_type = value_type (high);
- name = "std::ops::RangeTo";
+ name = (inclusive
+ ? "std::ops::RangeToInclusive" : "std::ops::RangeTo");
}
}
else
if (!types_equal (value_type (low), value_type (high)))
error (_("Range expression with different types"));
index_type = value_type (low);
- name = "std::ops::Range";
+ name = inclusive ? "std::ops::RangeInclusive" : "std::ops::Range";
}
}
*kind = (*kind == BOTH_BOUND_DEFAULT
? LOW_BOUND_DEFAULT : NONE_BOUND_DEFAULT);
*high = value_as_long (value_field (range, i));
+
+ if (rust_inclusive_range_type_p (type))
+ ++*high;
}
}
else
low = value_as_long (rhs);
+ struct type *type = check_typedef (value_type (lhs));
if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
- struct type *type = check_typedef (value_type (lhs));
+ struct type *base_type = nullptr;
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ base_type = TYPE_TARGET_TYPE (type);
+ else if (rust_slice_type_p (type))
+ {
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ if (strcmp (TYPE_FIELD_NAME (type, i), "data_ptr") == 0)
+ {
+ base_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, i));
+ break;
+ }
+ }
+ if (base_type == nullptr)
+ error (_("Could not find 'data_ptr' in slice type"));
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ base_type = TYPE_TARGET_TYPE (type);
+ else
+ error (_("Cannot subscript non-array type"));
- result = value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (lhs));
+ struct type *new_type;
+ if (want_slice)
+ {
+ if (rust_slice_type_p (type))
+ new_type = type;
+ else
+ {
+ struct type *usize
+ = language_lookup_primitive_type (exp->language_defn,
+ exp->gdbarch,
+ "usize");
+ new_type = rust_slice_type ("&[*gdb*]", base_type, usize);
+ }
+ }
+ else
+ new_type = base_type;
+
+ return value_zero (new_type, VALUE_LVAL (lhs));
}
else
{
LONGEST low_bound;
struct value *base;
- struct type *type = check_typedef (value_type (lhs));
if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
{
usize = language_lookup_primitive_type (exp->language_defn,
exp->gdbarch,
"usize");
- slice = rust_slice_type ("&[*gdb*]", value_type (result),
- usize);
+ const char *new_name = ((type != nullptr
+ && rust_slice_type_p (type))
+ ? TYPE_NAME (type) : "&[*gdb*]");
+
+ slice = rust_slice_type (new_name, value_type (result), usize);
addrval = value_allocate_space_in_inferior (TYPE_LENGTH (slice));
addr = value_as_long (addrval);
switch (exp->elts[*pos].opcode)
{
+ case UNOP_IND:
+ {
+ if (noside != EVAL_NORMAL)
+ result = evaluate_subexp_standard (expect_type, exp, pos, noside);
+ else
+ {
+ ++*pos;
+ struct value *value = evaluate_subexp (expect_type, exp, pos,
+ noside);
+
+ struct value *trait_ptr = rust_get_trait_object_pointer (value);
+ if (trait_ptr != NULL)
+ value = trait_ptr;
+
+ result = value_ind (value);
+ }
+ }
+ break;
+
case UNOP_COMPLEMENT:
{
struct value *value;
case OP_RUST_ARRAY:
{
- int pc = (*pos)++;
+ (*pos)++;
int copies;
struct value *elt;
struct value *ncopies;
if (noside == EVAL_NORMAL)
{
- CORE_ADDR addr;
int i;
std::vector<struct value *> eltvec (copies);
/* Anonymous field access, i.e. foo.1. */
struct value *lhs;
int pc, field_number, nfields;
- struct type *type, *variant_type;
- struct disr_info disr;
+ struct type *type;
pc = (*pos)++;
field_number = longest_to_int (exp->elts[pc + 1].longconst);
lhs = evaluate_subexp (NULL_TYPE, exp, pos, noside);
type = value_type (lhs);
- /* Untagged unions can't have anonymous field access since
- they can only have named fields. */
- if (TYPE_CODE (type) == TYPE_CODE_UNION
- && !rust_union_is_untagged (type))
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
{
- disr = rust_get_disr_info (type, value_contents (lhs),
- value_embedded_offset (lhs),
- value_address (lhs), lhs);
+ struct type *outer_type = NULL;
- if (disr.is_encoded && disr.field_no == RUST_ENCODED_ENUM_HIDDEN)
- {
- variant_type = NULL;
- nfields = 0;
- }
- else
+ if (rust_enum_p (type))
{
- variant_type = TYPE_FIELD_TYPE (type, disr.field_no);
- nfields = TYPE_NFIELDS (variant_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);
+
+ struct value *union_value = value_primitive_field (lhs, 0, 0,
+ type);
+
+ int fieldno = (variant_field
+ - &TYPE_FIELD (value_type (union_value), 0));
+ lhs = value_primitive_field (union_value, 0, fieldno,
+ value_type (union_value));
+ outer_type = type;
+ type = value_type (lhs);
}
- if (!disr.is_encoded)
- ++field_number;
-
- if (field_number >= nfields || field_number < 0)
- error(_("Cannot access field %d of variant %s, \
-there are only %d fields"),
- disr.is_encoded ? field_number : field_number - 1,
- disr.name.c_str (),
- disr.is_encoded ? nfields : nfields - 1);
-
- if (!(disr.is_encoded
- ? rust_tuple_struct_type_p (variant_type)
- : rust_tuple_variant_type_p (variant_type)))
- error(_("Variant %s is not a tuple variant"), disr.name.c_str ());
-
- result = value_primitive_field (lhs, 0, field_number,
- variant_type);
- }
- else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
- {
/* Tuples and tuple structs */
- nfields = TYPE_NFIELDS(type);
+ nfields = TYPE_NFIELDS (type);
if (field_number >= nfields || field_number < 0)
- error(_("Cannot access field %d of %s, there are only %d fields"),
- field_number, TYPE_TAG_NAME (type), nfields);
+ {
+ if (outer_type != NULL)
+ error(_("Cannot access field %d of variant %s::%s, "
+ "there are only %d fields"),
+ field_number, TYPE_NAME (outer_type),
+ rust_last_path_segment (TYPE_NAME (type)),
+ nfields);
+ else
+ error(_("Cannot access field %d of %s, "
+ "there are only %d fields"),
+ field_number, TYPE_NAME (type), nfields);
+ }
/* Tuples are tuple structs too. */
if (!rust_tuple_struct_type_p (type))
- error(_("Attempting to access anonymous field %d of %s, which is \
-not a tuple, tuple struct, or tuple-like variant"),
- field_number, TYPE_TAG_NAME (type));
+ {
+ if (outer_type != NULL)
+ error(_("Variant %s::%s is not a tuple variant"),
+ TYPE_NAME (outer_type),
+ rust_last_path_segment (TYPE_NAME (type)));
+ else
+ error(_("Attempting to access anonymous field %d "
+ "of %s, which is not a tuple, tuple struct, or "
+ "tuple-like variant"),
+ field_number, TYPE_NAME (type));
+ }
result = value_primitive_field (lhs, 0, field_number, type);
}
case STRUCTOP_STRUCT:
{
- struct value* lhs;
+ struct value *lhs;
struct type *type;
int tem, pc;
(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
lhs = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ const char *field_name = &exp->elts[pc + 2].string;
type = value_type (lhs);
- if (TYPE_CODE (type) == TYPE_CODE_UNION
- && !rust_union_is_untagged (type))
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT && rust_enum_p (type))
{
- int i, start;
- struct disr_info disr;
- struct type* variant_type;
- char* field_name;
-
- field_name = &exp->elts[pc + 2].string;
-
- disr = rust_get_disr_info (type, value_contents (lhs),
- value_embedded_offset (lhs),
- value_address (lhs), lhs);
-
- if (disr.is_encoded && disr.field_no == RUST_ENCODED_ENUM_HIDDEN)
- error(_("Could not find field %s of struct variant %s"),
- field_name, disr.name.c_str ());
-
- variant_type = TYPE_FIELD_TYPE (type, disr.field_no);
-
- if (variant_type == NULL
- || (disr.is_encoded
- ? rust_tuple_struct_type_p (variant_type)
- : rust_tuple_variant_type_p (variant_type)))
- error(_("Attempting to access named field %s of tuple variant %s, \
-which has only anonymous fields"),
- field_name, disr.name.c_str ());
-
- start = disr.is_encoded ? 0 : 1;
- for (i = start; i < TYPE_NFIELDS (variant_type); i++)
+ 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 value *union_value = value_primitive_field (lhs, 0, 0,
+ type);
+
+ int fieldno = (variant_field
+ - &TYPE_FIELD (value_type (union_value), 0));
+ lhs = value_primitive_field (union_value, 0, fieldno,
+ value_type (union_value));
+
+ 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 %s of tuple "
+ "variant %s::%s, which has only anonymous fields"),
+ field_name, TYPE_NAME (outer_type),
+ rust_last_path_segment (TYPE_NAME (type)));
+
+ try
{
- if (strcmp (TYPE_FIELD_NAME (variant_type, i),
- field_name) == 0) {
- result = value_primitive_field (lhs, 0, i, variant_type);
- break;
- }
+ result = value_struct_elt (&lhs, NULL, field_name,
+ NULL, "structure");
+ }
+ catch (const gdb_exception_error &except)
+ {
+ error (_("Could not find field %s of struct variant %s::%s"),
+ field_name, TYPE_NAME (outer_type),
+ rust_last_path_segment (TYPE_NAME (type)));
}
-
- if (i == TYPE_NFIELDS (variant_type))
- /* We didn't find it. */
- error(_("Could not find field %s of struct variant %s"),
- field_name, disr.name.c_str ());
}
else
- {
- /* Field access in structs and untagged unions works like C. */
- *pos = pc;
- result = evaluate_subexp_standard (expect_type, exp, pos, noside);
- }
+ result = value_struct_elt (&lhs, NULL, field_name, NULL, "structure");
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ result = value_zero (value_type (result), VALUE_LVAL (result));
}
break;
/* op_name implementation for Rust. */
-static char *
+static const char *
rust_op_name (enum exp_opcode opcode)
{
switch (opcode)
{
int field_number;
- field_number = longest_to_int (exp->elts[elt].longconst);
+ field_number = longest_to_int (exp->elts[elt + 1].longconst);
fprintf_filtered (stream, "Field number: %d", field_number);
- elt = dump_subexp (exp, stream, elt + 2);
+ elt = dump_subexp (exp, stream, elt + 3);
}
break;
case OP_RUST_ARRAY:
+ ++elt;
break;
default:
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf_filtered (stream, ".%d", tem);
}
- return;
+ break;
case OP_RUST_ARRAY:
++*pos;
const struct block *block,
const domain_enum domain)
{
- struct block_symbol result = {NULL, NULL};
+ struct block_symbol result = {};
if (symbol_lookup_debug)
{
}
/* Look up bare names in the block's scope. */
+ std::string scopedname;
if (name[cp_find_first_component (name)] == '\0')
{
const char *scope = block_scope (block);
if (scope[0] != '\0')
{
- std::string scopedname = std::string (scope) + "::" + name;
-
- result = lookup_symbol_in_static_block (scopedname.c_str (), block,
- domain);
- if (result.symbol == NULL)
- result = lookup_global_symbol (scopedname.c_str (), block, domain);
+ scopedname = std::string (scope) + "::" + name;
+ name = scopedname.c_str ();
}
+ else
+ name = NULL;
+ }
+
+ if (name != NULL)
+ {
+ result = lookup_symbol_in_static_block (name, block, domain);
+ if (result.symbol == NULL)
+ result = lookup_global_symbol (name, block, domain);
}
return result;
}
\f
+/* la_watch_location_expression for Rust. */
+
+static gdb::unique_xmalloc_ptr<char>
+rust_watch_location_expression (struct type *type, CORE_ADDR addr)
+{
+ type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
+ std::string name = type_to_string (type);
+ return gdb::unique_xmalloc_ptr<char>
+ (xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr),
+ name.c_str ()));
+}
+
+\f
+
static const struct exp_descriptor exp_descriptor_rust =
{
rust_print_subexp,
".rs", NULL
};
-static const struct language_defn rust_language_defn =
+extern const struct language_defn rust_language_defn =
{
"rust",
"Rust",
rust_extensions,
&exp_descriptor_rust,
rust_parse,
- rustyyerror,
null_post_parser,
rust_printchar, /* Print a character constant */
rust_printstr, /* Function to print string constant */
default_read_var_value, /* la_read_var_value */
NULL, /* Language specific skip_trampoline */
NULL, /* name_of_this */
+ false, /* la_store_sym_names_in_linkage_form_p */
rust_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
basic_lookup_transparent_type,/* lookup_transparent_type */
gdb_demangle, /* Language specific symbol demangler */
1, /* c-style arrays */
0, /* String lower bound */
default_word_break_characters,
- default_make_symbol_completion_list,
+ default_collect_symbol_completion_matches,
rust_language_arch_info,
default_print_array_index,
default_pass_by_reference,
- c_get_string,
- NULL, /* la_get_symbol_name_cmp */
+ rust_watch_location_expression,
+ NULL, /* la_get_symbol_name_matcher */
iterate_over_symbols,
+ default_search_name_hash,
&default_varobj_ops,
NULL,
NULL,
- LANG_MAGIC
+ rust_is_string_type_p,
+ "{...}" /* la_struct_too_deep_ellipsis */
};
-
-void
-_initialize_rust_language (void)
-{
- add_language (&rust_language_defn);
-}