From fb933624929d0716f25db8d1096557e7f5e72440 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 13 Jul 2006 04:31:42 +0000 Subject: [PATCH] gdb/ * infcall.c (value_arg_coerce): Use value_cast_pointers for references. Avoid value_cast to a reference type. Don't silently convert pointers to references. * valops.c (value_cast_pointers): New, based on value_cast. (value_cast): Use it. Reject reference types. (value_ref): New. (typecmp): Use it. * value.h (value_cast_pointers, value_ref): New prototypes. gdb/testsuite/ * gdb.cp/ref-params.exp: New test. * gdb.cp/ref-params.cc: New source file. * gdb.cp/Makefile.in (EXECUTABLES): Add ref-params. --- gdb/ChangeLog | 12 +++ gdb/infcall.c | 22 +++-- gdb/testsuite/ChangeLog | 7 ++ gdb/testsuite/gdb.cp/Makefile.in | 3 +- gdb/testsuite/gdb.cp/ref-params.cc | 80 +++++++++++++++++ gdb/testsuite/gdb.cp/ref-params.exp | 79 +++++++++++++++++ gdb/valops.c | 130 ++++++++++++++++++---------- gdb/value.h | 4 + 8 files changed, 284 insertions(+), 53 deletions(-) create mode 100644 gdb/testsuite/gdb.cp/ref-params.cc create mode 100644 gdb/testsuite/gdb.cp/ref-params.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4cd5bde6aaa..5ce4c8019c0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2006-07-13 Paul N. Hilfinger + Daniel Jacobowitz + + * infcall.c (value_arg_coerce): Use value_cast_pointers for + references. Avoid value_cast to a reference type. Don't silently + convert pointers to references. + * valops.c (value_cast_pointers): New, based on value_cast. + (value_cast): Use it. Reject reference types. + (value_ref): New. + (typecmp): Use it. + * value.h (value_cast_pointers, value_ref): New prototypes. + 2006-07-12 Daniel Jacobowitz * remote.c (unpack_varlen_hex): Correct type of retval. diff --git a/gdb/infcall.c b/gdb/infcall.c index c8a63348ee3..3a1ad6aba7e 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -109,14 +109,20 @@ value_arg_coerce (struct value *arg, struct type *param_type, switch (TYPE_CODE (type)) { case TYPE_CODE_REF: - if (TYPE_CODE (arg_type) != TYPE_CODE_REF - && TYPE_CODE (arg_type) != TYPE_CODE_PTR) - { - arg = value_addr (arg); - deprecated_set_value_type (arg, param_type); - return arg; - } - break; + { + struct value *new_value; + + if (TYPE_CODE (arg_type) == TYPE_CODE_REF) + return value_cast_pointers (type, arg); + + /* Cast the value to the reference's target type, and then + convert it back to a reference. This will issue an error + if the value was not previously in memory - in some cases + we should clearly be allowing this, but how? */ + new_value = value_cast (TYPE_TARGET_TYPE (type), arg); + new_value = value_ref (new_value); + return new_value; + } case TYPE_CODE_INT: case TYPE_CODE_CHAR: case TYPE_CODE_BOOL: diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 7e239a72b62..d811e0ebfd2 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2006-07-13 Paul N. Hilfinger + Daniel Jacobowitz + + * gdb.cp/ref-params.exp: New test. + * gdb.cp/ref-params.cc: New source file. + * gdb.cp/Makefile.in (EXECUTABLES): Add ref-params. + 2006-07-08 Mark Kettenis * gdb.arch/alpha-step.exp (test_stepi): Do not include trailing diff --git a/gdb/testsuite/gdb.cp/Makefile.in b/gdb/testsuite/gdb.cp/Makefile.in index 8f4a90e2bb2..06846505ab6 100644 --- a/gdb/testsuite/gdb.cp/Makefile.in +++ b/gdb/testsuite/gdb.cp/Makefile.in @@ -3,7 +3,8 @@ srcdir = @srcdir@ EXECUTABLES = ambiguous annota2 anon-union cplusfuncs cttiadd \ derivation inherit local member-ptr method misc \ - overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace ref-types + overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace \ + ref-types ref-params all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc new file mode 100644 index 00000000000..9ccfe09c1a0 --- /dev/null +++ b/gdb/testsuite/gdb.cp/ref-params.cc @@ -0,0 +1,80 @@ +/* This test script is part of GDB, the GNU debugger. + + Copyright 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Author: Paul N. Hilfinger, AdaCore Inc. */ + +struct Parent { + Parent (int id0) : id(id0) { } + int id; +}; + +struct Child : public Parent { + Child (int id0) : Parent(id0) { } +}; + +int f1(Parent& R) +{ + return R.id; /* Set breakpoint marker3 here. */ +} + +int f2(Child& C) +{ + return f1(C); /* Set breakpoint marker2 here. */ +} + +struct OtherParent { + OtherParent (int other_id0) : other_id(other_id0) { } + int other_id; +}; + +struct MultiChild : public Parent, OtherParent { + MultiChild (int id0) : Parent(id0), OtherParent(id0 * 2) { } +}; + +int mf1(OtherParent& R) +{ + return R.other_id; +} + +int mf2(MultiChild& C) +{ + return mf1(C); +} + +int main(void) +{ + Child Q(42); + Child& QR = Q; + + #ifdef usestubs + set_debug_traps(); + breakpoint(); + #endif + + /* Set breakpoint marker1 here. */ + + f2(Q); + f2(QR); + + MultiChild MQ(53); + MultiChild& MQR = MQ; + + mf2(MQ); /* Set breakpoint MQ here. */ +} diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp new file mode 100644 index 00000000000..8ad0198ddb4 --- /dev/null +++ b/gdb/testsuite/gdb.cp/ref-params.exp @@ -0,0 +1,79 @@ +# Tests for reference parameters of types and their subtypes in GDB. +# Copyright 2006 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# written by Paul N. Hilfinger (Hilfinger@adacore.com) + +if $tracelevel then { + strace $tracelevel + } + +# +# test running programs +# +set prms_id 0 +set bug_id 0 + +if { [skip_cplus_tests] } { continue } + +set testfile "ref-params" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit + +proc gdb_start_again { text } { + global srcdir + global subdir + global binfile + global srcfile + + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + + runto ${srcfile}:[gdb_get_line_number $text] +} + +gdb_start_again "marker1 here" +gdb_test "print Q" ".*id = 42.*" "print value of a Child in main" +gdb_test "print f1(Q)" ".* = 42.*" "print value of f1 on Child in main" +gdb_test "print f2(Q)" ".* = 42.*" "print value of f2 on Child in main" + +gdb_start_again "marker1 here" +gdb_test "print f1(QR)" ".* = 42.*" "print value of f1 on (Child&) in main" + +gdb_start_again "marker1 here" +gdb_test "print f2(QR)" ".* = 42.*" "print value of f2 on (Child&) in main" + +gdb_start_again "marker2 here" +gdb_test "print C" ".*id = 42.*" "print value of Child& in f2" +gdb_test "print f1(C)" ".* = 42.*" "print value of f1 on Child& in f2" + +gdb_start_again "marker3 here" +gdb_test "print R" ".*id = 42.*" "print value of Parent& in f1" + +gdb_start_again "breakpoint MQ here" +gdb_test "print f1(MQ)" ".* = 53" +gdb_test "print mf1(MQ)" ".* = 106" +gdb_test "print mf2(MQ)" ".* = 106" +gdb_test "print f1(MQR)" ".* = 53" +gdb_test "print mf1(MQR)" ".* = 106" +gdb_test "print mf2(MQR)" ".* = 106" diff --git a/gdb/valops.c b/gdb/valops.c index e86b532e40b..7d1b7d83e70 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -201,6 +201,70 @@ allocate_space_in_inferior (int len) return value_as_long (value_allocate_space_in_inferior (len)); } +/* 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. */ + +struct value * +value_cast_pointers (struct type *type, struct value *arg2) +{ + struct type *type2 = check_typedef (value_type (arg2)); + struct type *t1 = check_typedef (TYPE_TARGET_TYPE (type)); + struct type *t2 = check_typedef (TYPE_TARGET_TYPE (type2)); + + if (TYPE_CODE (t1) == TYPE_CODE_STRUCT + && TYPE_CODE (t2) == TYPE_CODE_STRUCT + && !value_logical_not (arg2)) + { + struct value *v; + + /* Look in the type of the source to see if it contains the + type of the target as a superclass. If so, we'll need to + offset the pointer rather than just change its type. */ + if (TYPE_NAME (t1) != NULL) + { + struct value *v2; + + if (TYPE_CODE (type2) == TYPE_CODE_REF) + v2 = coerce_ref (arg2); + else + v2 = value_ind (arg2); + v = search_struct_field (type_name_no_tag (t1), + v2, 0, t2, 1); + if (v) + { + v = value_addr (v); + deprecated_set_value_type (v, type); + return v; + } + } + + /* Look in the type of the target to see if it contains the + type of the source as a superclass. If so, we'll need to + offset the pointer rather than just change its type. + FIXME: This fails silently with virtual inheritance. */ + if (TYPE_NAME (t2) != NULL) + { + v = search_struct_field (type_name_no_tag (t2), + value_zero (t1, not_lval), 0, t1, 1); + if (v) + { + CORE_ADDR addr2 = value_as_address (arg2); + addr2 -= (VALUE_ADDRESS (v) + + value_offset (v) + + value_embedded_offset (v)); + return value_from_pointer (type, addr2); + } + } + } + + /* No superclass found, just change the pointer type. */ + deprecated_set_value_type (arg2, type); + arg2 = value_change_enclosing_type (arg2, type); + set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */ + return arg2; +} + /* Cast value ARG2 to type TYPE and return as a value. More general than a C cast: accepts any two types of the same length, and if ARG2 is an lvalue it can be cast into anything at all. */ @@ -224,6 +288,10 @@ value_cast (struct type *type, struct value *arg2) arg2 = coerce_ref (arg2); type2 = check_typedef (value_type (arg2)); + /* You can't cast to a reference type. See value_cast_pointers + instead. */ + gdb_assert (code1 != TYPE_CODE_REF); + /* A cast to an undetermined-length array_type, such as (TYPE [])OBJECT, is treated like a cast to (TYPE [N])OBJECT, where N is sizeof(OBJECT)/sizeof(TYPE). */ @@ -369,50 +437,8 @@ 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) - { - struct type *t1 = check_typedef (TYPE_TARGET_TYPE (type)); - struct type *t2 = check_typedef (TYPE_TARGET_TYPE (type2)); - if (TYPE_CODE (t1) == TYPE_CODE_STRUCT - && TYPE_CODE (t2) == TYPE_CODE_STRUCT - && !value_logical_not (arg2)) - { - struct value *v; - - /* Look in the type of the source to see if it contains the - type of the target as a superclass. If so, we'll need to - offset the pointer rather than just change its type. */ - if (TYPE_NAME (t1) != NULL) - { - v = search_struct_field (type_name_no_tag (t1), - value_ind (arg2), 0, t2, 1); - if (v) - { - v = value_addr (v); - deprecated_set_value_type (v, type); - return v; - } - } + return value_cast_pointers (type, arg2); - /* Look in the type of the target to see if it contains the - type of the source as a superclass. If so, we'll need to - offset the pointer rather than just change its type. - FIXME: This fails silently with virtual inheritance. */ - if (TYPE_NAME (t2) != NULL) - { - v = search_struct_field (type_name_no_tag (t2), - value_zero (t1, not_lval), 0, t1, 1); - if (v) - { - CORE_ADDR addr2 = value_as_address (arg2); - addr2 -= (VALUE_ADDRESS (v) - + value_offset (v) - + value_embedded_offset (v)); - return value_from_pointer (type, addr2); - } - } - } - /* No superclass found, just fall through to change ptr type. */ - } deprecated_set_value_type (arg2, type); arg2 = value_change_enclosing_type (arg2, type); set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */ @@ -886,6 +912,22 @@ value_addr (struct value *arg1) return arg2; } +/* Return a reference value for the object for which ARG1 is the contents. */ + +struct value * +value_ref (struct value *arg1) +{ + struct value *arg2; + + struct type *type = check_typedef (value_type (arg1)); + if (TYPE_CODE (type) == TYPE_CODE_REF) + return arg1; + + arg2 = value_addr (arg1); + deprecated_set_value_type (arg2, lookup_reference_type (type)); + return arg2; +} + /* Given a value of a pointer type, apply the C unary * operator to it. */ struct value * @@ -1106,7 +1148,7 @@ typecmp (int staticp, int varargs, int nargs, if (TYPE_CODE (tt2) == TYPE_CODE_ARRAY) t2[i] = value_coerce_array (t2[i]); else - t2[i] = value_addr (t2[i]); + t2[i] = value_ref (t2[i]); continue; } diff --git a/gdb/value.h b/gdb/value.h index a878ec4008d..87129d61216 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -325,6 +325,8 @@ extern struct value *value_ind (struct value *arg1); extern struct value *value_addr (struct value *arg1); +extern struct value *value_ref (struct value *arg1); + extern struct value *value_assign (struct value *toval, struct value *fromval); @@ -367,6 +369,8 @@ extern struct type *value_rtti_target_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 (struct type *type, struct value *arg2); extern struct value *value_zero (struct type *type, enum lval_type lv); -- 2.30.2