From b1af9e975066c48b043c5234199effd47115b4d4 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 21 May 2012 19:47:54 +0000 Subject: [PATCH] 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) : 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. --- gdb/ChangeLog | 17 +++++ gdb/ada-lang.c | 2 +- gdb/eval.c | 4 +- gdb/gnu-v3-abi.c | 5 +- gdb/infcall.c | 2 +- gdb/testsuite/ChangeLog | 6 ++ gdb/testsuite/gdb.cp/inherit.exp | 77 ++++------------------- gdb/valops.c | 133 ++++++++++++++++++++++++++++----------- gdb/value.h | 2 +- 9 files changed, 139 insertions(+), 109 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5fd2f3c..c12d3fd 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,22 @@ 2012-05-21 Tom Tromey + 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) : Use + value_cast_pointers. + * ada-lang.c (ada_convert_actual): Update. + +2012-05-21 Tom Tromey + * macroexp.c (macro_stringify): Terminate the string. 2012-05-20 Jan Kratochvil diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 72d4768..1fac316 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -4139,7 +4139,7 @@ ada_convert_actual (struct value *actual, struct type *formal_type0) } else 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) return ada_value_ind (actual); diff --git a/gdb/eval.c b/gdb/eval.c index 59d8bff..7f1dfac 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -2047,8 +2047,8 @@ evaluate_subexp_standard (struct type *expect_type, case TYPE_CODE_MEMBERPTR: /* Now, convert these values to an address. */ - arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), - arg1); + arg1 = value_cast_pointers (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg1, 1); mem_offset = value_as_long (arg2); diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 42b939d..3a83e2d 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -430,8 +430,9 @@ gnuv3_baseclass_offset (struct type *type, int index, ptr_type = builtin_type (gdbarch)->builtin_data_ptr; /* If it isn't a virtual base, this is easy. The offset is in the - type definition. */ - if (!BASETYPE_VIA_VIRTUAL (type, index)) + type definition. Likewise for Java, which doesn't really have + virtual inheritance in the C++ sense. */ + if (!BASETYPE_VIA_VIRTUAL (type, index) || TYPE_CPLUS_REALLY_JAVA (type)) return TYPE_BASECLASS_BITPOS (type, index) / 8; /* To access a virtual base, we need to use the vbase offset stored in diff --git a/gdb/infcall.c b/gdb/infcall.c index 4ace08b..8d7c621 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -159,7 +159,7 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, struct value *new_value; 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 convert it back to a reference. This will issue an error diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8e36471..21809b8 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2012-05-21 Tom Tromey + * gdb.cp/inherit.exp (test_print_mi_members): Expect errors. + Remove kfails. + (test_print_mi_member_types): Likewise. + +2012-05-21 Tom Tromey + * gdb.base/callfuncs.exp (do_function_calls): Update for 'set print symbol' change. diff --git a/gdb/testsuite/gdb.cp/inherit.exp b/gdb/testsuite/gdb.cp/inherit.exp index 7e2e871..7a59053 100644 --- a/gdb/testsuite/gdb.cp/inherit.exp +++ b/gdb/testsuite/gdb.cp/inherit.exp @@ -321,25 +321,11 @@ proc test_print_mi_members {} { # Print all members of g_D. # - # g_D.A::a and g_D.A::x are ambiguous member accesses, and gdb - # 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 "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" - } - } - + # g_D.A::a and g_D.A::x are ambiguous member accesses. + gdb_test "print g_D.A::a" "base class 'A' is ambiguous in type 'D'" + gdb_test "print g_D.C::a" "$vhn = 15" + gdb_test "print g_D.B::a" "$vhn = 11" + gdb_test "print g_D.A::x" "base class 'A' is ambiguous in type 'D'" gdb_test "print g_D.B::b" "$vhn = 13" gdb_test "print g_D.B::x" "$vhn = 14" gdb_test "print g_D.C::c" "$vhn = 17" @@ -350,20 +336,8 @@ proc test_print_mi_members {} { # Print all members of g_E. # g_E.A::a and g_E.A::x are ambiguous. - set name "print g_E.A::a" - gdb_test_multiple "print g_E.A::a" $name { - -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.A::a" "base class 'A' is ambiguous in type 'E'" + gdb_test "print g_E.A::x" "base class 'A' is ambiguous in type 'E'" gdb_test "print g_E.B::b" "$vhn = 23" gdb_test "print g_E.B::x" "$vhn = 24" 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. # - # g_D.A::a and g_D.A::x are ambiguous member accesses, and gdb - # 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" - } - } + # g_D.A::a and g_D.A::x are ambiguous member accesses. + 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::x" "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. # g_E.A::a and g_E.A::x are ambiguous. - set name "ptype g_E.A::a" - gdb_test_multiple "ptype g_E.A::a" $name { - -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.A::a" "base class 'A' is ambiguous in type 'E'" + gdb_test "ptype g_E.A::x" "base class 'A' is ambiguous in type 'E'" gdb_test "ptype g_E.B::b" "type = int" gdb_test "ptype g_E.B::x" "type = int" gdb_test "ptype g_E.C::c" "type = int" diff --git a/gdb/valops.c b/gdb/valops.c index ee450e3..feb47f5 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -301,10 +301,14 @@ value_cast_structs (struct type *type, struct value *v2) /* Cast one pointer or reference type to another. Both TYPE and 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 * -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 *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 && TYPE_CODE (t2) == TYPE_CODE_STRUCT - && !value_logical_not (arg2)) + && (subclass_check || !value_logical_not (arg2))) { struct value *v2; @@ -568,7 +572,7 @@ value_cast (struct type *type, struct value *arg2) else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2)) { 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); deprecated_set_value_type (arg2, type); @@ -1976,17 +1980,41 @@ typecmp (int staticp, int varargs, int nargs, return i + 1; } -/* 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. +/* Helper class for do_search_struct_field that updates *RESULT_PTR + and *LAST_BOFFSET, and possibly throws an exception if the field + search has yielded ambiguous results. */ - If LOOKING_FOR_BASECLASS, then instead of looking for struct - fields, look for a baseclass named NAME. */ +static void +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 * -search_struct_field (const char *name, struct value *arg1, int offset, - struct type *type, int looking_for_baseclass) +/* A helper for search_struct_field. This does all the work; most + arguments are as passed to search_struct_field. The result is + 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 nbases; @@ -2012,12 +2040,9 @@ search_struct_field (const char *name, struct value *arg1, int offset, name); } else - { - v = value_primitive_field (arg1, offset, i, type); - if (v == 0) - error (_("there is no field named %s"), name); - } - return v; + v = value_primitive_field (arg1, offset, i, type); + *result_ptr = v; + return; } 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 . */ - struct value *v; + struct value *v = NULL; int new_offset = offset; /* 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)) new_offset += TYPE_FIELD_BITPOS (type, i) / 8; - v = search_struct_field (name, arg1, new_offset, - field_type, - looking_for_baseclass); + do_search_struct_field (name, arg1, new_offset, + field_type, + looking_for_baseclass, &v, + last_boffset, + outermost_type); if (v) - return v; + { + *result_ptr = v; + return; + } } } } for (i = 0; i < nbases; i++) { - struct value *v; + struct value *v = NULL; struct type *basetype = check_typedef (TYPE_BASECLASS (type, i)); /* 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 @@ -2077,10 +2107,10 @@ search_struct_field (const char *name, struct value *arg1, int offset, && (strcmp_iw (name, TYPE_BASECLASS_NAME (type, i)) == 0)); + int boffset = value_embedded_offset (arg1) + offset; if (BASETYPE_VIA_VIRTUAL (type, i)) { - int boffset; struct value *v2; boffset = baseclass_offset (type, i, @@ -2116,22 +2146,51 @@ search_struct_field (const char *name, struct value *arg1, int offset, } if (found_baseclass) - return v2; - v = search_struct_field (name, v2, 0, - TYPE_BASECLASS (type, i), - looking_for_baseclass); + v = v2; + else + { + do_search_struct_field (name, v2, 0, + TYPE_BASECLASS (type, i), + looking_for_baseclass, + result_ptr, last_boffset, + outermost_type); + } } else if (found_baseclass) v = value_primitive_field (arg1, offset, i, type); else - v = search_struct_field (name, arg1, - offset + TYPE_BASECLASS_BITPOS (type, - i) / 8, - basetype, looking_for_baseclass); - if (v) - return v; + { + do_search_struct_field (name, arg1, + offset + TYPE_BASECLASS_BITPOS (type, + i) / 8, + basetype, looking_for_baseclass, + result_ptr, last_boffset, + outermost_type); + } + + update_search_result (result_ptr, v, last_boffset, + boffset, name, outermost_type); } - return NULL; +} + +/* 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 diff --git a/gdb/value.h b/gdb/value.h index 25013d8..b630fc7 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -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, 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); -- 2.7.4