PR c++/7173:

* gnu-v3-abi.c (gnuv3_baseclass_offset): Return early for Java
	types.
	* value.h (value_cast_pointers): Update.
	* valops.c (value_cast_pointers): Add 'subclass_check' argument.
	(value_cast): Update.
	(update_search_result): New function.
	(do_search_struct_field): New, from search_struct_field.  Check
	for ambiguous results.
	(search_struct_field): Rewrite.
	* infcall.c (value_arg_coerce): Update.
	* eval.c (evaluate_subexp_standard) <STRUCTOP_MEMBER>: Use
	value_cast_pointers.
	* ada-lang.c (ada_convert_actual): Update.
testsuite
	* gdb.cp/inherit.exp (test_print_mi_members): Expect errors.
	Remove kfails.
	(test_print_mi_member_types): Likewise.
This commit is contained in:
Tom Tromey 2012-05-21 19:47:54 +00:00
parent 248537e34b
commit b1af9e9750
9 changed files with 139 additions and 109 deletions

View file

@ -1,3 +1,20 @@
2012-05-21 Tom Tromey <tromey@redhat.com>
PR c++/7173:
* gnu-v3-abi.c (gnuv3_baseclass_offset): Return early for Java
types.
* value.h (value_cast_pointers): Update.
* valops.c (value_cast_pointers): Add 'subclass_check' argument.
(value_cast): Update.
(update_search_result): New function.
(do_search_struct_field): New, from search_struct_field. Check
for ambiguous results.
(search_struct_field): Rewrite.
* infcall.c (value_arg_coerce): Update.
* eval.c (evaluate_subexp_standard) <STRUCTOP_MEMBER>: Use
value_cast_pointers.
* ada-lang.c (ada_convert_actual): Update.
2012-05-21 Tom Tromey <tromey@redhat.com> 2012-05-21 Tom Tromey <tromey@redhat.com>
* macroexp.c (macro_stringify): Terminate the string. * macroexp.c (macro_stringify): Terminate the string.

View file

@ -4139,7 +4139,7 @@ ada_convert_actual (struct value *actual, struct type *formal_type0)
} }
else else
return actual; return actual;
return value_cast_pointers (formal_type, result); return value_cast_pointers (formal_type, result, 0);
} }
else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR) else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR)
return ada_value_ind (actual); return ada_value_ind (actual);

View file

@ -2047,8 +2047,8 @@ evaluate_subexp_standard (struct type *expect_type,
case TYPE_CODE_MEMBERPTR: case TYPE_CODE_MEMBERPTR:
/* Now, convert these values to an address. */ /* Now, convert these values to an address. */
arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), arg1 = value_cast_pointers (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
arg1); arg1, 1);
mem_offset = value_as_long (arg2); mem_offset = value_as_long (arg2);

View file

@ -430,8 +430,9 @@ gnuv3_baseclass_offset (struct type *type, int index,
ptr_type = builtin_type (gdbarch)->builtin_data_ptr; ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
/* If it isn't a virtual base, this is easy. The offset is in the /* If it isn't a virtual base, this is easy. The offset is in the
type definition. */ type definition. Likewise for Java, which doesn't really have
if (!BASETYPE_VIA_VIRTUAL (type, index)) virtual inheritance in the C++ sense. */
if (!BASETYPE_VIA_VIRTUAL (type, index) || TYPE_CPLUS_REALLY_JAVA (type))
return TYPE_BASECLASS_BITPOS (type, index) / 8; return TYPE_BASECLASS_BITPOS (type, index) / 8;
/* To access a virtual base, we need to use the vbase offset stored in /* To access a virtual base, we need to use the vbase offset stored in

View file

@ -159,7 +159,7 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
struct value *new_value; struct value *new_value;
if (TYPE_CODE (arg_type) == TYPE_CODE_REF) if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
return value_cast_pointers (type, arg); return value_cast_pointers (type, arg, 0);
/* Cast the value to the reference's target type, and then /* Cast the value to the reference's target type, and then
convert it back to a reference. This will issue an error convert it back to a reference. This will issue an error

View file

@ -1,3 +1,9 @@
2012-05-21 Tom Tromey <tromey@redhat.com>
* gdb.cp/inherit.exp (test_print_mi_members): Expect errors.
Remove kfails.
(test_print_mi_member_types): Likewise.
2012-05-21 Tom Tromey <tromey@redhat.com> 2012-05-21 Tom Tromey <tromey@redhat.com>
* gdb.base/callfuncs.exp (do_function_calls): Update for 'set * gdb.base/callfuncs.exp (do_function_calls): Update for 'set

View file

@ -321,25 +321,11 @@ proc test_print_mi_members {} {
# Print all members of g_D. # Print all members of g_D.
# #
# g_D.A::a and g_D.A::x are ambiguous member accesses, and gdb # g_D.A::a and g_D.A::x are ambiguous member accesses.
# should detect these. There are no ways to PASS these tests gdb_test "print g_D.A::a" "base class 'A' is ambiguous in type 'D'"
# because I don't know what the gdb message will be. -- chastain gdb_test "print g_D.C::a" "$vhn = 15"
# 2004-01-27. gdb_test "print g_D.B::a" "$vhn = 11"
gdb_test "print g_D.A::x" "base class 'A' is ambiguous in type 'D'"
set name "print g_D.A::a"
gdb_test_multiple "print g_D.A::a" $name {
-re "$vhn = (15|11)$nl$gdb_prompt $" {
kfail "gdb/68" "print g_D.A::a"
}
}
set name "print g_D.A::x"
gdb_test_multiple "print g_D.A::x" $name {
-re "$vhn = (16|12)$nl$gdb_prompt $" {
kfail "gdb/68" "print g_D.A::x"
}
}
gdb_test "print g_D.B::b" "$vhn = 13" gdb_test "print g_D.B::b" "$vhn = 13"
gdb_test "print g_D.B::x" "$vhn = 14" gdb_test "print g_D.B::x" "$vhn = 14"
gdb_test "print g_D.C::c" "$vhn = 17" gdb_test "print g_D.C::c" "$vhn = 17"
@ -350,20 +336,8 @@ proc test_print_mi_members {} {
# Print all members of g_E. # Print all members of g_E.
# g_E.A::a and g_E.A::x are ambiguous. # g_E.A::a and g_E.A::x are ambiguous.
set name "print g_E.A::a" gdb_test "print g_E.A::a" "base class 'A' is ambiguous in type 'E'"
gdb_test_multiple "print g_E.A::a" $name { gdb_test "print g_E.A::x" "base class 'A' is ambiguous in type 'E'"
-re "$vhn = (21|25)$nl$gdb_prompt $" {
kfail "gdb/68" "print g_E.A::a"
}
}
set name "print g_E.A::x"
gdb_test_multiple "print g_E.A::x" $name {
-re "$vhn = (26|22)$nl$gdb_prompt $" {
kfail "gdb/68" "print g_E.A::x"
}
}
gdb_test "print g_E.B::b" "$vhn = 23" gdb_test "print g_E.B::b" "$vhn = 23"
gdb_test "print g_E.B::x" "$vhn = 24" gdb_test "print g_E.B::x" "$vhn = 24"
gdb_test "print g_E.C::c" "$vhn = 27" gdb_test "print g_E.C::c" "$vhn = 27"
@ -406,25 +380,10 @@ proc test_print_mi_member_types {} {
# Print all members of g_D. # Print all members of g_D.
# #
# g_D.A::a and g_D.A::x are ambiguous member accesses, and gdb # g_D.A::a and g_D.A::x are ambiguous member accesses.
# should detect these. There are no ways to PASS these tests
# because I don't know what the gdb message will be. -- chastain
# 2004-01-27.
set name "ptype g_D.A::a"
gdb_test_multiple "ptype g_D.A::a" $name {
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_D.A::a"
}
}
set name "ptype g_D.A::x"
gdb_test_multiple "ptype g_D.A::x" $name {
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_D.A::x"
}
}
gdb_test "ptype g_D.A::a" "base class 'A' is ambiguous in type 'D'"
gdb_test "ptype g_D.A::x" "base class 'A' is ambiguous in type 'D'"
gdb_test "ptype g_D.B::b" "type = int" gdb_test "ptype g_D.B::b" "type = int"
gdb_test "ptype g_D.B::x" "type = int" gdb_test "ptype g_D.B::x" "type = int"
gdb_test "ptype g_D.C::c" "type = int" gdb_test "ptype g_D.C::c" "type = int"
@ -435,20 +394,8 @@ proc test_print_mi_member_types {} {
# Print all members of g_E. # Print all members of g_E.
# g_E.A::a and g_E.A::x are ambiguous. # g_E.A::a and g_E.A::x are ambiguous.
set name "ptype g_E.A::a" gdb_test "ptype g_E.A::a" "base class 'A' is ambiguous in type 'E'"
gdb_test_multiple "ptype g_E.A::a" $name { gdb_test "ptype g_E.A::x" "base class 'A' is ambiguous in type 'E'"
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_E.A::a"
}
}
set name "ptype g_E.A::x"
gdb_test_multiple "ptype g_E.A::x" $name {
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_E.A::x"
}
}
gdb_test "ptype g_E.B::b" "type = int" gdb_test "ptype g_E.B::b" "type = int"
gdb_test "ptype g_E.B::x" "type = int" gdb_test "ptype g_E.B::x" "type = int"
gdb_test "ptype g_E.C::c" "type = int" gdb_test "ptype g_E.C::c" "type = int"

View file

@ -301,10 +301,14 @@ value_cast_structs (struct type *type, struct value *v2)
/* Cast one pointer or reference type to another. Both TYPE and /* Cast one pointer or reference type to another. Both TYPE and
the type of ARG2 should be pointer types, or else both should be the type of ARG2 should be pointer types, or else both should be
reference types. Returns the new pointer or reference. */ reference types. If SUBCLASS_CHECK is non-zero, this will force a
check to see whether TYPE is a superclass of ARG2's type. If
SUBCLASS_CHECK is zero, then the subclass check is done only when
ARG2 is itself non-zero. Returns the new pointer or reference. */
struct value * struct value *
value_cast_pointers (struct type *type, struct value *arg2) value_cast_pointers (struct type *type, struct value *arg2,
int subclass_check)
{ {
struct type *type1 = check_typedef (type); struct type *type1 = check_typedef (type);
struct type *type2 = check_typedef (value_type (arg2)); struct type *type2 = check_typedef (value_type (arg2));
@ -313,7 +317,7 @@ value_cast_pointers (struct type *type, struct value *arg2)
if (TYPE_CODE (t1) == TYPE_CODE_STRUCT if (TYPE_CODE (t1) == TYPE_CODE_STRUCT
&& TYPE_CODE (t2) == TYPE_CODE_STRUCT && TYPE_CODE (t2) == TYPE_CODE_STRUCT
&& !value_logical_not (arg2)) && (subclass_check || !value_logical_not (arg2)))
{ {
struct value *v2; struct value *v2;
@ -568,7 +572,7 @@ value_cast (struct type *type, struct value *arg2)
else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2)) else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2))
{ {
if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
return value_cast_pointers (type, arg2); return value_cast_pointers (type, arg2, 0);
arg2 = value_copy (arg2); arg2 = value_copy (arg2);
deprecated_set_value_type (arg2, type); deprecated_set_value_type (arg2, type);
@ -1976,17 +1980,41 @@ typecmp (int staticp, int varargs, int nargs,
return i + 1; return i + 1;
} }
/* Helper function used by value_struct_elt to recurse through /* Helper class for do_search_struct_field that updates *RESULT_PTR
baseclasses. Look for a field NAME in ARG1. Adjust the address of and *LAST_BOFFSET, and possibly throws an exception if the field
ARG1 by OFFSET bytes, and search in it assuming it has (class) type search has yielded ambiguous results. */
TYPE. If found, return value, else return NULL.
If LOOKING_FOR_BASECLASS, then instead of looking for struct static void
fields, look for a baseclass named NAME. */ update_search_result (struct value **result_ptr, struct value *v,
int *last_boffset, int boffset,
const char *name, struct type *type)
{
if (v != NULL)
{
if (*result_ptr != NULL
/* The result is not ambiguous if all the classes that are
found occupy the same space. */
&& *last_boffset != boffset)
error (_("base class '%s' is ambiguous in type '%s'"),
name, TYPE_SAFE_NAME (type));
*result_ptr = v;
*last_boffset = boffset;
}
}
static struct value * /* A helper for search_struct_field. This does all the work; most
search_struct_field (const char *name, struct value *arg1, int offset, arguments are as passed to search_struct_field. The result is
struct type *type, int looking_for_baseclass) stored in *RESULT_PTR, which must be initialized to NULL.
OUTERMOST_TYPE is the type of the initial type passed to
search_struct_field; this is used for error reporting when the
lookup is ambiguous. */
static void
do_search_struct_field (const char *name, struct value *arg1, int offset,
struct type *type, int looking_for_baseclass,
struct value **result_ptr,
int *last_boffset,
struct type *outermost_type)
{ {
int i; int i;
int nbases; int nbases;
@ -2012,12 +2040,9 @@ search_struct_field (const char *name, struct value *arg1, int offset,
name); name);
} }
else else
{
v = value_primitive_field (arg1, offset, i, type); v = value_primitive_field (arg1, offset, i, type);
if (v == 0) *result_ptr = v;
error (_("there is no field named %s"), name); return;
}
return v;
} }
if (t_field_name if (t_field_name
@ -2042,7 +2067,7 @@ search_struct_field (const char *name, struct value *arg1, int offset,
represented as a struct, with a member for each represented as a struct, with a member for each
<variant field>. */ <variant field>. */
struct value *v; struct value *v = NULL;
int new_offset = offset; int new_offset = offset;
/* This is pretty gross. In G++, the offset in an /* This is pretty gross. In G++, the offset in an
@ -2056,18 +2081,23 @@ search_struct_field (const char *name, struct value *arg1, int offset,
&& TYPE_FIELD_BITPOS (field_type, 0) == 0)) && TYPE_FIELD_BITPOS (field_type, 0) == 0))
new_offset += TYPE_FIELD_BITPOS (type, i) / 8; new_offset += TYPE_FIELD_BITPOS (type, i) / 8;
v = search_struct_field (name, arg1, new_offset, do_search_struct_field (name, arg1, new_offset,
field_type, field_type,
looking_for_baseclass); looking_for_baseclass, &v,
last_boffset,
outermost_type);
if (v) if (v)
return v; {
*result_ptr = v;
return;
}
} }
} }
} }
for (i = 0; i < nbases; i++) for (i = 0; i < nbases; i++)
{ {
struct value *v; struct value *v = NULL;
struct type *basetype = check_typedef (TYPE_BASECLASS (type, i)); struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
/* If we are looking for baseclasses, this is what we get when /* If we are looking for baseclasses, this is what we get when
we hit them. But it could happen that the base part's member we hit them. But it could happen that the base part's member
@ -2077,10 +2107,10 @@ search_struct_field (const char *name, struct value *arg1, int offset,
&& (strcmp_iw (name, && (strcmp_iw (name,
TYPE_BASECLASS_NAME (type, TYPE_BASECLASS_NAME (type,
i)) == 0)); i)) == 0));
int boffset = value_embedded_offset (arg1) + offset;
if (BASETYPE_VIA_VIRTUAL (type, i)) if (BASETYPE_VIA_VIRTUAL (type, i))
{ {
int boffset;
struct value *v2; struct value *v2;
boffset = baseclass_offset (type, i, boffset = baseclass_offset (type, i,
@ -2116,22 +2146,51 @@ search_struct_field (const char *name, struct value *arg1, int offset,
} }
if (found_baseclass) if (found_baseclass)
return v2; v = v2;
v = search_struct_field (name, v2, 0, else
{
do_search_struct_field (name, v2, 0,
TYPE_BASECLASS (type, i), TYPE_BASECLASS (type, i),
looking_for_baseclass); looking_for_baseclass,
result_ptr, last_boffset,
outermost_type);
}
} }
else if (found_baseclass) else if (found_baseclass)
v = value_primitive_field (arg1, offset, i, type); v = value_primitive_field (arg1, offset, i, type);
else else
v = search_struct_field (name, arg1, {
do_search_struct_field (name, arg1,
offset + TYPE_BASECLASS_BITPOS (type, offset + TYPE_BASECLASS_BITPOS (type,
i) / 8, i) / 8,
basetype, looking_for_baseclass); basetype, looking_for_baseclass,
if (v) result_ptr, last_boffset,
return v; outermost_type);
} }
return NULL;
update_search_result (result_ptr, v, last_boffset,
boffset, name, outermost_type);
}
}
/* Helper function used by value_struct_elt to recurse through
baseclasses. Look for a field NAME in ARG1. Adjust the address of
ARG1 by OFFSET bytes, and search in it assuming it has (class) type
TYPE. If found, return value, else return NULL.
If LOOKING_FOR_BASECLASS, then instead of looking for struct
fields, look for a baseclass named NAME. */
static struct value *
search_struct_field (const char *name, struct value *arg1, int offset,
struct type *type, int looking_for_baseclass)
{
struct value *result = NULL;
int boffset = 0;
do_search_struct_field (name, arg1, offset, type, looking_for_baseclass,
&result, &boffset, type);
return result;
} }
/* Helper function used by value_struct_elt to recurse through /* Helper function used by value_struct_elt to recurse through

View file

@ -669,7 +669,7 @@ extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
extern struct value *value_full_object (struct value *, struct type *, int, extern struct value *value_full_object (struct value *, struct type *, int,
int, int); int, int);
extern struct value *value_cast_pointers (struct type *, struct value *); extern struct value *value_cast_pointers (struct type *, struct value *, int);
extern struct value *value_cast (struct type *type, struct value *arg2); extern struct value *value_cast (struct type *type, struct value *arg2);