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:
Tom Tromey 2010-01-18 20:54:35 +00:00
parent d9c57d9ff1
commit 4e8f195d9d
13 changed files with 602 additions and 16 deletions

View File

@ -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.

View File

@ -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];
}

View File

@ -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);

View File

@ -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, " (");

View File

@ -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

View File

@ -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;
}

View File

@ -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])

View File

@ -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;

View File

@ -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>

View File

@ -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 */
}

View File

@ -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"

View File

@ -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 *

View File

@ -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);