X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Frust-lang.c;h=9123bf2146d516dabb72f9d9caff728dced98ef0;hb=abb78b78c4184d2ac968362229adae268385a21c;hp=d9807d0ac1a41ee5b9e883cd5b684a318b50f6eb;hpb=69d340c68449f238fe665abf4a3a7989cd2d8376;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c index d9807d0ac1..9123bf2146 100644 --- a/gdb/rust-lang.c +++ b/gdb/rust-lang.c @@ -1,6 +1,6 @@ /* 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. @@ -31,10 +31,13 @@ #include "objfiles.h" #include "psymtab.h" #include "rust-lang.h" +#include "typeprint.h" #include "valprint.h" #include "varobj.h" +#include #include #include +#include "cli/cli-style.h" /* See rust-lang.h. */ @@ -72,9 +75,22 @@ rust_enum_p (const struct type *type) && 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. */ @@ -211,6 +227,26 @@ rust_chartype_p (struct type *type) && 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. */ @@ -343,6 +379,14 @@ val_print_struct (struct type *type, int embedded_offset, 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; } @@ -427,6 +471,15 @@ rust_print_enum (struct type *type, int embedded_offset, 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[%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; @@ -616,14 +669,14 @@ static void 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)) @@ -636,6 +689,13 @@ rust_print_struct_def (struct type *type, const char *varstring, 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); @@ -655,6 +715,18 @@ rust_print_struct_def (struct type *type, const char *varstring, 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 @@ -674,16 +746,41 @@ rust_print_struct_def (struct type *type, const char *varstring, 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 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 @@ -691,27 +788,35 @@ rust_print_struct_def (struct type *type, const char *varstring, /* 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); } @@ -724,9 +829,9 @@ rust_print_typedef (struct type *type, 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. */ @@ -735,10 +840,8 @@ static void 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) @@ -772,13 +875,13 @@ rust_internal_print_type (struct type *type, const char *varstring, 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. */ @@ -786,7 +889,7 @@ rust_internal_print_type (struct type *type, const char *varstring, { fputs_filtered (" -> ", stream); rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream, - -1, 0, flags, false); + -1, 0, flags, false, podata); } break; @@ -796,7 +899,8 @@ rust_internal_print_type (struct type *type, const char *varstring, 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) @@ -811,12 +915,12 @@ rust_internal_print_type (struct type *type, const char *varstring, 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) @@ -827,7 +931,7 @@ rust_internal_print_type (struct type *type, const char *varstring, } 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); @@ -845,6 +949,20 @@ rust_internal_print_type (struct type *type, const char *varstring, } 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); @@ -856,8 +974,9 @@ rust_print_type (struct type *type, const char *varstring, 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); } @@ -1084,7 +1203,7 @@ rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside) 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; } @@ -1511,7 +1630,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp, case OP_RUST_ARRAY: { - int pc = (*pos)++; + (*pos)++; int copies; struct value *elt; struct value *ncopies; @@ -1545,7 +1664,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp, /* 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); @@ -1560,6 +1679,10 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp, 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); @@ -1628,6 +1751,10 @@ tuple structs, and tuple-like enum variants")); 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); @@ -1642,23 +1769,22 @@ tuple structs, and tuple-like enum variants")); 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 + 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_NAME (outer_type), rust_last_path_segment (TYPE_NAME (type))); } - END_CATCH } else result = value_struct_elt (&lhs, NULL, field_name, NULL, "structure"); @@ -1924,7 +2050,7 @@ rust_lookup_symbol_nonlocal (const struct language_defn *langdef, const struct block *block, const domain_enum domain) { - struct block_symbol result = {NULL, NULL}; + struct block_symbol result = {}; if (symbol_lookup_debug) { @@ -2039,7 +2165,6 @@ extern const struct language_defn rust_language_defn = 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, @@ -2047,5 +2172,6 @@ extern const struct language_defn rust_language_defn = &default_varobj_ops, NULL, NULL, - LANG_MAGIC + rust_is_string_type_p, + "{...}" /* la_struct_too_deep_ellipsis */ };