diff options
author | Tom Tromey <tromey@redhat.com> | 2010-01-18 20:54:35 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2010-01-18 20:54:35 +0000 |
commit | 4e8f195d9dd0be6a5caf9349883db5a531aabd5f (patch) | |
tree | 4135b82af0d720a7a7e9786de58cf7cfc9486885 /gdb/valops.c | |
parent | d9c57d9ff1bf3533ddb272717afe2b18f61dd017 (diff) | |
download | gdb-4e8f195d9dd0be6a5caf9349883db5a531aabd5f.zip gdb-4e8f195d9dd0be6a5caf9349883db5a531aabd5f.tar.gz gdb-4e8f195d9dd0be6a5caf9349883db5a531aabd5f.tar.bz2 |
gdb
PR c++/9680:
* c-exp.y (REINTERPRET_CAST, DYNAMIC_CAST, STATIC_CAST)
(CONST_CAST): New tokens.
(exp): Add new productions.
(ident_tokens): Add const_cast, dynamic_cast, static_cast, and
reinterpret_cast.
(is_cast_operator): New function.
(yylex): Handle cast operators specially.
* eval.c (evaluate_subexp_standard) <UNOP_DYNAMIC_CAST,
UNOP_REINTERPRET_CAST>: New cases.
* expprint.c (print_subexp_standard): Likewise.
(op_name_standard): Likewise.
(dump_subexp_body_standard): Likewise.
* parse.c (operator_length_standard): Likewise.
* expression.h (enum exp_opcode): New constants UNOP_DYNAMIC_CAST,
UNOP_REINTERPRET_CAST.
* gdbtypes.c (class_types_same_p): New function.
(is_ancestor): Use it.
(is_public_ancestor): New function.
(is_unique_ancestor_worker): Likewise.
(is_unique_ancestor): Likewise.
* gdbtypes.h (class_types_same_p, is_public_ancestor)
(is_unique_ancestor): Declare.
* valops.c (value_reinterpret_cast): New function.
(dynamic_cast_check_1): Likewise.
(dynamic_cast_check_2): Likewise.
(value_dynamic_cast): Likewise.
* value.h (value_reinterpret_cast, value_dynamic_cast): Declare.
gdb/testsuite
PR c++/9680:
* gdb.cp/casts.cc: Add new classes and variables.
* gdb.cp/casts.exp: Test new operators.
Diffstat (limited to 'gdb/valops.c')
-rw-r--r-- | gdb/valops.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/gdb/valops.c b/gdb/valops.c index 1667368..ca34083 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -527,6 +527,258 @@ value_cast (struct type *type, struct value *arg2) } } +/* The C++ reinterpret_cast operator. */ + +struct value * +value_reinterpret_cast (struct type *type, struct value *arg) +{ + struct value *result; + struct type *real_type = check_typedef (type); + struct type *arg_type, *dest_type; + int is_ref = 0; + enum type_code dest_code, arg_code; + + /* Do reference, function, and array conversion. */ + arg = coerce_array (arg); + + /* Attempt to preserve the type the user asked for. */ + dest_type = type; + + /* If we are casting to a reference type, transform + reinterpret_cast<T&>(V) to *reinterpret_cast<T*>(&V). */ + if (TYPE_CODE (real_type) == TYPE_CODE_REF) + { + is_ref = 1; + arg = value_addr (arg); + dest_type = lookup_pointer_type (TYPE_TARGET_TYPE (dest_type)); + real_type = lookup_pointer_type (real_type); + } + + arg_type = value_type (arg); + + dest_code = TYPE_CODE (real_type); + arg_code = TYPE_CODE (arg_type); + + /* We can convert pointer types, or any pointer type to int, or int + type to pointer. */ + if ((dest_code == TYPE_CODE_PTR && arg_code == TYPE_CODE_INT) + || (dest_code == TYPE_CODE_INT && arg_code == TYPE_CODE_PTR) + || (dest_code == TYPE_CODE_METHODPTR && arg_code == TYPE_CODE_INT) + || (dest_code == TYPE_CODE_INT && arg_code == TYPE_CODE_METHODPTR) + || (dest_code == TYPE_CODE_MEMBERPTR && arg_code == TYPE_CODE_INT) + || (dest_code == TYPE_CODE_INT && arg_code == TYPE_CODE_MEMBERPTR) + || (dest_code == arg_code + && (dest_code == TYPE_CODE_PTR + || dest_code == TYPE_CODE_METHODPTR + || dest_code == TYPE_CODE_MEMBERPTR))) + result = value_cast (dest_type, arg); + else + error (_("Invalid reinterpret_cast")); + + if (is_ref) + result = value_cast (type, value_ref (value_ind (result))); + + return result; +} + +/* A helper for value_dynamic_cast. This implements the first of two + runtime checks: we iterate over all the base classes of the value's + class which are equal to the desired class; if only one of these + holds the value, then it is the answer. */ + +static int +dynamic_cast_check_1 (struct type *desired_type, + const bfd_byte *contents, + CORE_ADDR address, + struct type *search_type, + CORE_ADDR arg_addr, + struct type *arg_type, + struct value **result) +{ + int i, result_count = 0; + + for (i = 0; i < TYPE_N_BASECLASSES (search_type) && result_count < 2; ++i) + { + int offset = baseclass_offset (search_type, i, contents, address); + if (offset == -1) + error (_("virtual baseclass botch")); + if (class_types_same_p (desired_type, TYPE_BASECLASS (search_type, i))) + { + if (address + offset >= arg_addr + && address + offset < arg_addr + TYPE_LENGTH (arg_type)) + { + ++result_count; + if (!*result) + *result = value_at_lazy (TYPE_BASECLASS (search_type, i), + address + offset); + } + } + else + result_count += dynamic_cast_check_1 (desired_type, + contents + offset, + address + offset, + TYPE_BASECLASS (search_type, i), + arg_addr, + arg_type, + result); + } + + return result_count; +} + +/* A helper for value_dynamic_cast. This implements the second of two + runtime checks: we look for a unique public sibling class of the + argument's declared class. */ + +static int +dynamic_cast_check_2 (struct type *desired_type, + const bfd_byte *contents, + CORE_ADDR address, + struct type *search_type, + struct value **result) +{ + int i, result_count = 0; + + for (i = 0; i < TYPE_N_BASECLASSES (search_type) && result_count < 2; ++i) + { + int offset; + + if (! BASETYPE_VIA_PUBLIC (search_type, i)) + continue; + + offset = baseclass_offset (search_type, i, contents, address); + if (offset == -1) + error (_("virtual baseclass botch")); + if (class_types_same_p (desired_type, TYPE_BASECLASS (search_type, i))) + { + ++result_count; + if (*result == NULL) + *result = value_at_lazy (TYPE_BASECLASS (search_type, i), + address + offset); + } + else + result_count += dynamic_cast_check_2 (desired_type, + contents + offset, + address + offset, + TYPE_BASECLASS (search_type, i), + result); + } + + return result_count; +} + +/* The C++ dynamic_cast operator. */ + +struct value * +value_dynamic_cast (struct type *type, struct value *arg) +{ + int unambiguous = 0, full, top, using_enc; + struct type *resolved_type = check_typedef (type); + struct type *arg_type = check_typedef (value_type (arg)); + struct type *class_type, *rtti_type; + struct value *result, *tem, *original_arg = arg; + CORE_ADDR addr; + int is_ref = TYPE_CODE (resolved_type) == TYPE_CODE_REF; + + if (TYPE_CODE (resolved_type) != TYPE_CODE_PTR + && TYPE_CODE (resolved_type) != TYPE_CODE_REF) + error (_("Argument to dynamic_cast must be a pointer or reference type")); + if (TYPE_CODE (TYPE_TARGET_TYPE (resolved_type)) != TYPE_CODE_VOID + && TYPE_CODE (TYPE_TARGET_TYPE (resolved_type)) != TYPE_CODE_CLASS) + error (_("Argument to dynamic_cast must be pointer to class or `void *'")); + + class_type = check_typedef (TYPE_TARGET_TYPE (resolved_type)); + if (TYPE_CODE (resolved_type) == TYPE_CODE_PTR) + { + if (TYPE_CODE (arg_type) != TYPE_CODE_PTR + && ! (TYPE_CODE (arg_type) == TYPE_CODE_INT + && value_as_long (arg) == 0)) + error (_("Argument to dynamic_cast does not have pointer type")); + if (TYPE_CODE (arg_type) == TYPE_CODE_PTR) + { + arg_type = check_typedef (TYPE_TARGET_TYPE (arg_type)); + if (TYPE_CODE (arg_type) != TYPE_CODE_CLASS) + error (_("Argument to dynamic_cast does not have pointer to class type")); + } + + /* Handle NULL pointers. */ + if (value_as_long (arg) == 0) + return value_zero (type, not_lval); + + arg = value_ind (arg); + } + else + { + if (TYPE_CODE (arg_type) != TYPE_CODE_CLASS) + error (_("Argument to dynamic_cast does not have class type")); + } + + /* If the classes are the same, just return the argument. */ + if (class_types_same_p (class_type, arg_type)) + return value_cast (type, arg); + + /* If the target type is a unique base class of the argument's + declared type, just cast it. */ + if (is_ancestor (class_type, arg_type)) + { + if (is_unique_ancestor (class_type, arg)) + return value_cast (type, original_arg); + error (_("Ambiguous dynamic_cast")); + } + + rtti_type = value_rtti_type (arg, &full, &top, &using_enc); + if (! rtti_type) + error (_("Couldn't determine value's most derived type for dynamic_cast")); + + /* Compute the most derived object's address. */ + addr = value_address (arg); + if (full) + { + /* Done. */ + } + else if (using_enc) + addr += top; + else + addr += top + value_embedded_offset (arg); + + /* dynamic_cast<void *> means to return a pointer to the + most-derived object. */ + if (TYPE_CODE (resolved_type) == TYPE_CODE_PTR + && TYPE_CODE (TYPE_TARGET_TYPE (resolved_type)) == TYPE_CODE_VOID) + return value_at_lazy (type, addr); + + tem = value_at (type, addr); + + /* The first dynamic check specified in 5.2.7. */ + if (is_public_ancestor (arg_type, TYPE_TARGET_TYPE (resolved_type))) + { + if (class_types_same_p (rtti_type, TYPE_TARGET_TYPE (resolved_type))) + return tem; + result = NULL; + if (dynamic_cast_check_1 (TYPE_TARGET_TYPE (resolved_type), + value_contents (tem), value_address (tem), + rtti_type, addr, + arg_type, + &result) == 1) + return value_cast (type, + is_ref ? value_ref (result) : value_addr (result)); + } + + /* The second dynamic check specified in 5.2.7. */ + result = NULL; + if (is_public_ancestor (arg_type, rtti_type) + && dynamic_cast_check_2 (TYPE_TARGET_TYPE (resolved_type), + value_contents (tem), value_address (tem), + rtti_type, &result) == 1) + return value_cast (type, + is_ref ? value_ref (result) : value_addr (result)); + + if (TYPE_CODE (resolved_type) == TYPE_CODE_PTR) + return value_zero (type, not_lval); + + error (_("dynamic_cast failed")); +} + /* Create a value of type TYPE that is zero, and return it. */ struct value * |