mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-01-18 15:02:42 +00:00
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.
This commit is contained in:
parent
d9c57d9ff1
commit
4e8f195d9d
@ -1,3 +1,34 @@
|
||||
2010-01-18 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
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.
|
||||
|
||||
2010-01-18 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
Fix build failure when building without Python support.
|
||||
|
65
gdb/c-exp.y
65
gdb/c-exp.y
@ -206,6 +206,7 @@ static struct stoken operator_stoken (const char *);
|
||||
%token ERROR
|
||||
%token NEW DELETE
|
||||
%type <sval> operator
|
||||
%token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST
|
||||
|
||||
/* Special type cases, put in to allow the parser to distinguish different
|
||||
legal basetypes. */
|
||||
@ -591,6 +592,32 @@ exp : SIZEOF '(' type ')' %prec UNARY
|
||||
write_exp_elt_opcode (OP_LONG); }
|
||||
;
|
||||
|
||||
exp : REINTERPRET_CAST '<' type '>' '(' exp ')' %prec UNARY
|
||||
{ write_exp_elt_opcode (UNOP_REINTERPRET_CAST);
|
||||
write_exp_elt_type ($3);
|
||||
write_exp_elt_opcode (UNOP_REINTERPRET_CAST); }
|
||||
;
|
||||
|
||||
exp : STATIC_CAST '<' type '>' '(' exp ')' %prec UNARY
|
||||
{ write_exp_elt_opcode (UNOP_CAST);
|
||||
write_exp_elt_type ($3);
|
||||
write_exp_elt_opcode (UNOP_CAST); }
|
||||
;
|
||||
|
||||
exp : DYNAMIC_CAST '<' type '>' '(' exp ')' %prec UNARY
|
||||
{ write_exp_elt_opcode (UNOP_DYNAMIC_CAST);
|
||||
write_exp_elt_type ($3);
|
||||
write_exp_elt_opcode (UNOP_DYNAMIC_CAST); }
|
||||
;
|
||||
|
||||
exp : CONST_CAST '<' type '>' '(' exp ')' %prec UNARY
|
||||
{ /* We could do more error checking here, but
|
||||
it doesn't seem worthwhile. */
|
||||
write_exp_elt_opcode (UNOP_CAST);
|
||||
write_exp_elt_type ($3);
|
||||
write_exp_elt_opcode (UNOP_CAST); }
|
||||
;
|
||||
|
||||
string_exp:
|
||||
STRING
|
||||
{
|
||||
@ -1894,7 +1921,12 @@ static const struct token ident_tokens[] =
|
||||
{"or", OROR, BINOP_END, 1},
|
||||
{"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, 1},
|
||||
{"xor", '^', OP_NULL, 1},
|
||||
{"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 1}
|
||||
{"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 1},
|
||||
|
||||
{"const_cast", CONST_CAST, OP_NULL, 1 },
|
||||
{"dynamic_cast", DYNAMIC_CAST, OP_NULL, 1 },
|
||||
{"static_cast", STATIC_CAST, OP_NULL, 1 },
|
||||
{"reinterpret_cast", REINTERPRET_CAST, OP_NULL, 1 }
|
||||
};
|
||||
|
||||
/* When we find that lexptr (the global var defined in parse.c) is
|
||||
@ -1972,6 +2004,16 @@ scan_macro_cleanup (void *dummy)
|
||||
obstack_free (&expansion_obstack, NULL);
|
||||
}
|
||||
|
||||
/* Return true iff the token represents a C++ cast operator. */
|
||||
|
||||
static int
|
||||
is_cast_operator (const char *token, int len)
|
||||
{
|
||||
return (! strncmp (token, "dynamic_cast", len)
|
||||
|| ! strncmp (token, "static_cast", len)
|
||||
|| ! strncmp (token, "reinterpret_cast", len)
|
||||
|| ! strncmp (token, "const_cast", len));
|
||||
}
|
||||
|
||||
/* The scope used for macro expansion. */
|
||||
static struct macro_scope *expression_macro_scope;
|
||||
@ -2235,16 +2277,19 @@ yylex (void)
|
||||
FIXME: This mishandles `print $a<4&&$a>3'. */
|
||||
|
||||
if (c == '<')
|
||||
{
|
||||
/* Scan ahead to get rest of the template specification. Note
|
||||
that we look ahead only when the '<' adjoins non-whitespace
|
||||
characters; for comparison expressions, e.g. "a < b > c",
|
||||
there must be spaces before the '<', etc. */
|
||||
{
|
||||
if (! is_cast_operator (tokstart, namelen))
|
||||
{
|
||||
/* Scan ahead to get rest of the template specification. Note
|
||||
that we look ahead only when the '<' adjoins non-whitespace
|
||||
characters; for comparison expressions, e.g. "a < b > c",
|
||||
there must be spaces before the '<', etc. */
|
||||
|
||||
char * p = find_template_name_end (tokstart + namelen);
|
||||
if (p)
|
||||
namelen = p - tokstart;
|
||||
break;
|
||||
char * p = find_template_name_end (tokstart + namelen);
|
||||
if (p)
|
||||
namelen = p - tokstart;
|
||||
}
|
||||
break;
|
||||
}
|
||||
c = tokstart[++namelen];
|
||||
}
|
||||
|
16
gdb/eval.c
16
gdb/eval.c
@ -2413,6 +2413,22 @@ evaluate_subexp_standard (struct type *expect_type,
|
||||
arg1 = value_cast (type, arg1);
|
||||
return arg1;
|
||||
|
||||
case UNOP_DYNAMIC_CAST:
|
||||
(*pos) += 2;
|
||||
type = exp->elts[pc + 1].type;
|
||||
arg1 = evaluate_subexp (type, exp, pos, noside);
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
return value_dynamic_cast (type, arg1);
|
||||
|
||||
case UNOP_REINTERPRET_CAST:
|
||||
(*pos) += 2;
|
||||
type = exp->elts[pc + 1].type;
|
||||
arg1 = evaluate_subexp (type, exp, pos, noside);
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
return value_reinterpret_cast (type, arg1);
|
||||
|
||||
case UNOP_MEMVAL:
|
||||
(*pos) += 2;
|
||||
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
|
||||
|
@ -410,6 +410,18 @@ print_subexp_standard (struct expression *exp, int *pos,
|
||||
fputs_filtered (")", stream);
|
||||
return;
|
||||
|
||||
case UNOP_DYNAMIC_CAST:
|
||||
case UNOP_REINTERPRET_CAST:
|
||||
fputs_filtered (opcode == UNOP_DYNAMIC_CAST ? "dynamic_cast"
|
||||
: "reinterpret_cast", stream);
|
||||
fputs_filtered ("<", stream);
|
||||
(*pos) += 2;
|
||||
type_print (exp->elts[pc + 1].type, "", stream, 0);
|
||||
fputs_filtered ("> (", stream);
|
||||
print_subexp (exp, pos, stream, PREC_PREFIX);
|
||||
fputs_filtered (")", stream);
|
||||
return;
|
||||
|
||||
case UNOP_MEMVAL:
|
||||
(*pos) += 2;
|
||||
if ((int) prec > (int) PREC_PREFIX)
|
||||
@ -730,6 +742,10 @@ op_name_standard (enum exp_opcode opcode)
|
||||
return "OP_ARRAY";
|
||||
case UNOP_CAST:
|
||||
return "UNOP_CAST";
|
||||
case UNOP_DYNAMIC_CAST:
|
||||
return "UNOP_DYNAMIC_CAST";
|
||||
case UNOP_REINTERPRET_CAST:
|
||||
return "UNOP_REINTERPRET_CAST";
|
||||
case UNOP_MEMVAL:
|
||||
return "UNOP_MEMVAL";
|
||||
case UNOP_MEMVAL_TLS:
|
||||
@ -1036,6 +1052,8 @@ dump_subexp_body_standard (struct expression *exp,
|
||||
break;
|
||||
case UNOP_MEMVAL:
|
||||
case UNOP_CAST:
|
||||
case UNOP_DYNAMIC_CAST:
|
||||
case UNOP_REINTERPRET_CAST:
|
||||
fprintf_filtered (stream, "Type @");
|
||||
gdb_print_host_address (exp->elts[elt].type, stream);
|
||||
fprintf_filtered (stream, " (");
|
||||
|
@ -233,6 +233,12 @@ enum exp_opcode
|
||||
It casts the value of the following subexpression. */
|
||||
UNOP_CAST,
|
||||
|
||||
/* The C++ dynamic_cast operator. */
|
||||
UNOP_DYNAMIC_CAST,
|
||||
|
||||
/* The C++ reinterpret_cast operator. */
|
||||
UNOP_REINTERPRET_CAST,
|
||||
|
||||
/* UNOP_MEMVAL is followed by a type pointer in the next exp_element
|
||||
With another UNOP_MEMVAL at the end, this makes three exp_elements.
|
||||
It casts the contents of the word addressed by the value of the
|
||||
|
109
gdb/gdbtypes.c
109
gdb/gdbtypes.c
@ -1838,6 +1838,18 @@ is_integral_type (struct type *t)
|
||||
|| (TYPE_CODE (t) == TYPE_CODE_BOOL)));
|
||||
}
|
||||
|
||||
/* A helper function which returns true if types A and B represent the
|
||||
"same" class type. This is true if the types have the same main
|
||||
type, or the same name. */
|
||||
|
||||
int
|
||||
class_types_same_p (const struct type *a, const struct type *b)
|
||||
{
|
||||
return (TYPE_MAIN_TYPE (a) == TYPE_MAIN_TYPE (b)
|
||||
|| (TYPE_NAME (a) && TYPE_NAME (b)
|
||||
&& !strcmp (TYPE_NAME (a), TYPE_NAME (b))));
|
||||
}
|
||||
|
||||
/* Check whether BASE is an ancestor or base class or DCLASS
|
||||
Return 1 if so, and 0 if not.
|
||||
Note: callers may want to check for identity of the types before
|
||||
@ -1852,18 +1864,103 @@ is_ancestor (struct type *base, struct type *dclass)
|
||||
CHECK_TYPEDEF (base);
|
||||
CHECK_TYPEDEF (dclass);
|
||||
|
||||
if (base == dclass)
|
||||
return 1;
|
||||
if (TYPE_NAME (base) && TYPE_NAME (dclass)
|
||||
&& !strcmp (TYPE_NAME (base), TYPE_NAME (dclass)))
|
||||
if (class_types_same_p (base, dclass))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < TYPE_N_BASECLASSES (dclass); i++)
|
||||
if (is_ancestor (base, TYPE_BASECLASS (dclass, i)))
|
||||
return 1;
|
||||
{
|
||||
if (is_ancestor (base, TYPE_BASECLASS (dclass, i)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Like is_ancestor, but only returns true when BASE is a public
|
||||
ancestor of DCLASS. */
|
||||
|
||||
int
|
||||
is_public_ancestor (struct type *base, struct type *dclass)
|
||||
{
|
||||
int i;
|
||||
|
||||
CHECK_TYPEDEF (base);
|
||||
CHECK_TYPEDEF (dclass);
|
||||
|
||||
if (class_types_same_p (base, dclass))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < TYPE_N_BASECLASSES (dclass); ++i)
|
||||
{
|
||||
if (! BASETYPE_VIA_PUBLIC (dclass, i))
|
||||
continue;
|
||||
if (is_public_ancestor (base, TYPE_BASECLASS (dclass, i)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A helper function for is_unique_ancestor. */
|
||||
|
||||
static int
|
||||
is_unique_ancestor_worker (struct type *base, struct type *dclass,
|
||||
int *offset,
|
||||
const bfd_byte *contents, CORE_ADDR address)
|
||||
{
|
||||
int i, count = 0;
|
||||
|
||||
CHECK_TYPEDEF (base);
|
||||
CHECK_TYPEDEF (dclass);
|
||||
|
||||
for (i = 0; i < TYPE_N_BASECLASSES (dclass) && count < 2; ++i)
|
||||
{
|
||||
struct type *iter = check_typedef (TYPE_BASECLASS (dclass, i));
|
||||
int this_offset = baseclass_offset (dclass, i, contents, address);
|
||||
|
||||
if (this_offset == -1)
|
||||
error (_("virtual baseclass botch"));
|
||||
|
||||
if (class_types_same_p (base, iter))
|
||||
{
|
||||
/* If this is the first subclass, set *OFFSET and set count
|
||||
to 1. Otherwise, if this is at the same offset as
|
||||
previous instances, do nothing. Otherwise, increment
|
||||
count. */
|
||||
if (*offset == -1)
|
||||
{
|
||||
*offset = this_offset;
|
||||
count = 1;
|
||||
}
|
||||
else if (this_offset == *offset)
|
||||
{
|
||||
/* Nothing. */
|
||||
}
|
||||
else
|
||||
++count;
|
||||
}
|
||||
else
|
||||
count += is_unique_ancestor_worker (base, iter, offset,
|
||||
contents + this_offset,
|
||||
address + this_offset);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Like is_ancestor, but only returns true if BASE is a unique base
|
||||
class of the type of VAL. */
|
||||
|
||||
int
|
||||
is_unique_ancestor (struct type *base, struct value *val)
|
||||
{
|
||||
int offset = -1;
|
||||
|
||||
return is_unique_ancestor_worker (base, value_type (val), &offset,
|
||||
value_contents (val),
|
||||
value_address (val)) == 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1367,8 +1367,14 @@ extern int get_vptr_fieldno (struct type *, struct type **);
|
||||
|
||||
extern int get_discrete_bounds (struct type *, LONGEST *, LONGEST *);
|
||||
|
||||
extern int class_types_same_p (const struct type *, const struct type *);
|
||||
|
||||
extern int is_ancestor (struct type *, struct type *);
|
||||
|
||||
extern int is_public_ancestor (struct type *, struct type *);
|
||||
|
||||
extern int is_unique_ancestor (struct type *, struct value *);
|
||||
|
||||
/* Overload resolution */
|
||||
|
||||
#define LENGTH_MATCH(bv) ((bv)->rank[0])
|
||||
|
@ -853,6 +853,8 @@ operator_length_standard (struct expression *expr, int endpos,
|
||||
|
||||
case BINOP_VAL:
|
||||
case UNOP_CAST:
|
||||
case UNOP_DYNAMIC_CAST:
|
||||
case UNOP_REINTERPRET_CAST:
|
||||
case UNOP_MEMVAL:
|
||||
oplen = 3;
|
||||
args = 1;
|
||||
|
@ -1,3 +1,9 @@
|
||||
2010-01-18 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
PR c++/9680:
|
||||
* gdb.cp/casts.cc: Add new classes and variables.
|
||||
* gdb.cp/casts.exp: Test new operators.
|
||||
|
||||
2010-01-18 Tom Tromey <tromey@redhat.com>
|
||||
Thiago Jung Bauermann <bauerman@br.ibm.com>
|
||||
|
||||
|
@ -10,6 +10,30 @@ struct B: public A
|
||||
B (int aa, int bb): A (aa), b(bb) {}
|
||||
};
|
||||
|
||||
|
||||
struct Alpha
|
||||
{
|
||||
virtual void x() { }
|
||||
};
|
||||
|
||||
struct Gamma
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived : public Alpha
|
||||
{
|
||||
};
|
||||
|
||||
struct VirtuallyDerived : public virtual Alpha
|
||||
{
|
||||
};
|
||||
|
||||
struct DoublyDerived : public VirtuallyDerived,
|
||||
public virtual Alpha,
|
||||
public Gamma
|
||||
{
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -18,5 +42,11 @@ main (int argc, char **argv)
|
||||
A &ar = *b;
|
||||
B &br = (B&)ar;
|
||||
|
||||
Derived derived;
|
||||
DoublyDerived doublyderived;
|
||||
|
||||
Alpha *ad = &derived;
|
||||
Alpha *add = &doublyderived;
|
||||
|
||||
return 0; /* breakpoint spot: casts.exp: 1 */
|
||||
}
|
||||
|
@ -98,3 +98,75 @@ gdb_test "print (B &) ar" ".* = .B.* {<A> = {a = 42}, b = 1729}" \
|
||||
# Check compiler casting
|
||||
gdb_test "print br" ".* = .B.* {<A> = {a = 42}, b = 1729}" \
|
||||
"let compiler cast base class reference to derived class reference"
|
||||
|
||||
|
||||
# A few basic tests of "new" casts.
|
||||
|
||||
gdb_test "print const_cast<const B *> (b)" " = \\(const B \\*\\) $hex" \
|
||||
"basic test of const_cast"
|
||||
|
||||
gdb_test "print const_cast<void *> (0)" " = \\(void \\*\\) 0x0" \
|
||||
"const_cast of 0"
|
||||
|
||||
gdb_test "print static_cast<A *> (b)" " = \\(A \\*\\) $hex" \
|
||||
"basic test of static_cast"
|
||||
|
||||
gdb_test "print static_cast<A &> (*b)" " = \\(A \\&\\) @$hex: {a = 42}" \
|
||||
"static_cast to reference type"
|
||||
|
||||
gdb_test "print reinterpret_cast<A *> (b)" " = \\(A \\*\\) $hex" \
|
||||
"basic test of reinterpret_cast"
|
||||
|
||||
gdb_test "print reinterpret_cast<void> (b)" "Invalid reinterpret_cast" \
|
||||
"test invalid reinterpret_cast"
|
||||
|
||||
gdb_test "print reinterpret_cast<A &> (*b)" " = \\(A \\&\\) @$hex: {a = 42}" \
|
||||
"reinterpret_cast to reference type"
|
||||
|
||||
# Tests of dynamic_cast.
|
||||
|
||||
set nonzero_hex "0x\[0-9A-Fa-f\]\[0-9A-Fa-f\]+"
|
||||
|
||||
gdb_test "print dynamic_cast<void> (a)" \
|
||||
".*must be a pointer or reference type" \
|
||||
"invalid dynamic_cast"
|
||||
|
||||
gdb_test "print dynamic_cast<void *> (0)" \
|
||||
" = \\(void \\*\\) 0x0" \
|
||||
"dynamic_cast of 0 to void*"
|
||||
|
||||
gdb_test "print dynamic_cast<Alpha *> (&derived)" \
|
||||
" = \\(Alpha \\*\\) $nonzero_hex" \
|
||||
"dynamic_cast simple upcast"
|
||||
|
||||
gdb_test "print dynamic_cast<Alpha *> (&doublyderived)" \
|
||||
" = \\(Alpha \\*\\) $nonzero_hex" \
|
||||
"dynamic_cast upcast to unique base"
|
||||
|
||||
gdb_test "print dynamic_cast<Alpha &> (derived)" \
|
||||
" = \\(Alpha \\&\\) @$nonzero_hex: {.* = $nonzero_hex}" \
|
||||
"dynamic_cast simple upcast to reference"
|
||||
|
||||
gdb_test "print dynamic_cast<Derived *> (ad)" \
|
||||
" = \\(Derived \\*\\) $nonzero_hex" \
|
||||
"dynamic_cast simple downcast"
|
||||
|
||||
gdb_test "print dynamic_cast<VirtuallyDerived *> (add)" \
|
||||
" = \\(VirtuallyDerived \\*\\) $nonzero_hex" \
|
||||
"dynamic_cast simple downcast to intermediate class"
|
||||
|
||||
gdb_test "print dynamic_cast<VirtuallyDerived *> (ad)" \
|
||||
" = \\(VirtuallyDerived \\*\\) 0x0" \
|
||||
"dynamic_cast to non-existing base"
|
||||
|
||||
gdb_test "print dynamic_cast<VirtuallyDerived &> (*ad)" \
|
||||
"dynamic_cast failed" \
|
||||
"dynamic_cast to reference to non-existing base"
|
||||
|
||||
gdb_test "print dynamic_cast<DoublyDerived *> (add)" \
|
||||
" = \\(DoublyDerived \\*\\) $nonzero_hex" \
|
||||
"dynamic_cast unique downcast"
|
||||
|
||||
gdb_test "print dynamic_cast<Gamma *> (add)" \
|
||||
" = \\(Gamma \\*\\) $nonzero_hex" \
|
||||
"dynamic_cast to sibling"
|
||||
|
252
gdb/valops.c
252
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 *
|
||||
|
@ -469,6 +469,11 @@ extern struct value *value_cast_pointers (struct type *, struct value *);
|
||||
|
||||
extern struct value *value_cast (struct type *type, struct value *arg2);
|
||||
|
||||
extern struct value *value_reinterpret_cast (struct type *type,
|
||||
struct value *arg);
|
||||
|
||||
extern struct value *value_dynamic_cast (struct type *type, struct value *arg);
|
||||
|
||||
extern struct value *value_zero (struct type *type, enum lval_type lv);
|
||||
|
||||
extern struct value *value_one (struct type *type, enum lval_type lv);
|
||||
|
Loading…
x
Reference in New Issue
Block a user