/* Rust language support routines for GDB, the GNU debugger.
- Copyright (C) 2016-2018 Free Software Foundation, Inc.
+ Copyright (C) 2016-2020 Free Software Foundation, Inc.
This file is part of GDB.
#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"
/* See rust-lang.h. */
&& 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. */
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
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
- || strcmp (TYPE_TAG_NAME (type), "&str") == 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. */
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|| TYPE_NFIELDS (type) > 2
- || TYPE_TAG_NAME (type) == NULL
- || strstr (TYPE_TAG_NAME (type), "::Range") == NULL)
+ || TYPE_NAME (type) == NULL
+ || strstr (TYPE_NAME (type), "::Range") == NULL)
return false;
if (TYPE_NFIELDS (type) == 0)
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 bool
&& 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. */
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;
}
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);
}
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;
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))
{
- fputs_filtered (TYPE_TAG_NAME (type), stream);
+ fputs_filtered (TYPE_NAME (type), stream);
return;
}
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_TAG_NAME (type);
+ 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);
- bool is_univariant = false;
int enum_discriminant_index = -1;
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
= (struct discriminant_info *) discriminant_prop->data.baton;
enum_discriminant_index = info->discriminant_index;
}
- else if (TYPE_CODE (type) == TYPE_CODE_UNION && TYPE_NFIELDS (type) == 1)
- {
- /* Probably a univariant enum. */
- fputs_filtered ("enum ", stream);
- is_univariant = true;
- }
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
fputs_filtered ("struct ", stream);
else
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);
- }
- else if (is_univariant)
- {
- const char *name
- = rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (type, i)));
- fputs_filtered (name, 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 || is_univariant) ? show : show - 1),
- level + 2, flags, is_enum || is_univariant);
- if (!for_rust_enum)
+ 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);
}
- 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);
}
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. */
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_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_PTR:
+ {
+ if (TYPE_NAME (type) != nullptr)
+ fputs_filtered (TYPE_NAME (type), stream);
+ else
+ {
+ /* We currently can't distinguish between pointers and
+ references. */
+ fputs_filtered ("*mut ", stream);
+ type_print (TYPE_TARGET_TYPE (type), "", stream, 0);
+ }
+ }
+ break;
+
default:
c_printer:
c_print_type (type, varstring, stream, show, level, flags);
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
-/* Compute the alignment of the type T. */
-
-static int
-rust_type_alignment (struct type *t)
-{
- 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;
- }
- }
-}
-
/* 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, NULL, 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;
}
}
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);
type = value_type (lhs);
- /* Treat a univariant union as if it were an enum. */
- if (TYPE_CODE (type) == TYPE_CODE_UNION && TYPE_NFIELDS (type) == 1)
- {
- lhs = value_primitive_field (lhs, 0, 0, type);
- type = value_type (lhs);
- }
-
if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
{
struct type *outer_type = NULL;
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);
if (outer_type != NULL)
error(_("Cannot access field %d of variant %s::%s, "
"there are only %d fields"),
- field_number, TYPE_TAG_NAME (outer_type),
- rust_last_path_segment (TYPE_TAG_NAME (type)),
+ 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_TAG_NAME (type), nfields);
+ field_number, TYPE_NAME (type), nfields);
}
/* Tuples are tuple structs too. */
{
if (outer_type != NULL)
error(_("Variant %s::%s is not a tuple variant"),
- TYPE_TAG_NAME (outer_type),
- rust_last_path_segment (TYPE_TAG_NAME (type)));
+ 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_TAG_NAME (type));
+ field_number, TYPE_NAME (type));
}
result = value_primitive_field (lhs, 0, field_number, type);
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_TAG_NAME (outer_type),
+ field_name, TYPE_NAME (outer_type),
rust_last_path_segment (TYPE_NAME (type)));
- TRY
+ try
{
result = value_struct_elt (&lhs, NULL, field_name,
NULL, "structure");
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
error (_("Could not find field %s of struct variant %s::%s"),
- field_name, TYPE_TAG_NAME (outer_type),
+ field_name, TYPE_NAME (outer_type),
rust_last_path_segment (TYPE_NAME (type)));
}
- END_CATCH
}
else
result = value_struct_elt (&lhs, NULL, field_name, NULL, "structure");
const struct block *block,
const domain_enum domain)
{
- struct block_symbol result = {NULL, NULL};
+ struct block_symbol result = {};
if (symbol_lookup_debug)
{
rust_extensions,
&exp_descriptor_rust,
rust_parse,
- rustyyerror,
null_post_parser,
rust_printchar, /* Print a character constant */
rust_printstr, /* Function to print string constant */
rust_language_arch_info,
default_print_array_index,
default_pass_by_reference,
- c_get_string,
rust_watch_location_expression,
NULL, /* la_get_symbol_name_matcher */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
- LANG_MAGIC
+ rust_is_string_type_p,
+ "{...}" /* la_struct_too_deep_ellipsis */
};