#include "gdbarch.h"
#include "infcall.h"
#include "objfiles.h"
+#include "psymtab.h"
#include "rust-lang.h"
#include "valprint.h"
#include "varobj.h"
#include <string>
#include <vector>
-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. */
{
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_TAG_NAME (type) != NULL
- && strncmp (TYPE_TAG_NAME (type), "&[", 2) == 0);
+ && (strncmp (TYPE_TAG_NAME (type), "&[", 2) == 0
+ || strcmp (TYPE_TAG_NAME (type), "&str") == 0));
}
/* Return true if TYPE is a range type, otherwise false. */
&& TYPE_UNSIGNED (type));
}
+/* 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
+/* 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_print_type branch for structs and untagged unions. */
static void
{
int i;
int first_field;
+
+ if (rust_slice_type_p (type) && strcmp (TYPE_NAME (type), "&str") == 0)
+ {
+ 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;
for (i = 0; i < TYPE_NFIELDS (type); ++i)
{
- const char *name;
-
QUIT;
if (field_is_static (&TYPE_FIELD (type, i)))
continue;
fputs_filtered ("[", stream);
rust_print_type (TYPE_TARGET_TYPE (type), NULL,
stream, show - 1, level, flags);
- fputs_filtered ("; ", stream);
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);
}
case TYPE_CODE_UNION:
{
/* ADT enums. */
- int i, len = 0;
+ int i;
/* Skip the discriminant field. */
int skip_to = 1;
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, num_args + 1, args.data ());
return result;
}
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;
if (noside == EVAL_NORMAL)
{
- CORE_ADDR addr;
int i;
std::vector<struct value *> eltvec (copies);
\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",
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
};
-
-void
-_initialize_rust_language (void)
-{
- add_language (&rust_language_defn);
-}