8sa1-binutils-gdb/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
Andrew Burgess 30ab358668 gdb: allow casting to rvalue reference in more cases
It is not currently possible to cast some values to an rvaule
reference.  This happens when simple scalar values are cast to an
rvalue reference of the same type, e.g.:

  int global_var;

Then in GDB:

  (gdb) p static_cast<int&&> (global_var)
  Attempt to take address of value not located in memory.

Which is clearly silly.

The problem is that as part of the cast an intermediate value is
created within GDB that becomes an lval_none rather than the original
lval_memory.  The casting logic basically goes like this:

The call tree that leads to the error looks like this:

  value_cast
    value_cast
    value_ref
      value_addr
        error

The first value_cast call is casting the value for 'global_var' to
type 'int&&'.  GDB spots that the target type is a reference, and so
calls value_cast again, this time casting 'global_var' to type 'int'.
We then call value_ref to convert the result of the second value_cast
into a reference.

Unfortunately, the second cast results in the value (for global_var)
changing from an lval_memory to an lval_none.  This is because int to
int casting calls extract_unsigned_integer and then
value_from_longest.

In theory value_cast has a check at its head that should help in this
case, the code is:

  if (value_type (arg2) == type)
    return arg2;

However, this only works in some cases.  In our case
'value_type (arg2)' will be an objfile owned type, while the type from
the expression parser 'int&&' will be gdbarch owned.  The pointers
will not be equal, but the meaning of the type will be equal.

I did consider making the int to int casting case smarter, but this
obviously is only one example.  We must also consider things like
float to float, or pointer to pointer....

So, I instead decided to try and make the initial check smarter.
Instead of a straight pointer comparison, I now propose that we use
types_deeply_equal.  If this is true then we are casting something
back to its current type, in which case we can preserve the lval
setting by using value_copy.

gdb/ChangeLog:

	* valops.c (value_cast): Call value_deeply_equal before performing
	any cast.

gdb/testsuite/ChangeLog:

	* gdb.cp/rvalue-ref-params.cc (f3): New function.
	(f4): New function.
	(global_int): New global variable.
	(global_float): Likeiwse.
	(main): Call both new functions.
	* gdb.cp/rvalue-ref-params.exp: Add new tests.
2021-04-07 12:49:12 +01:00

78 lines
2.5 KiB
Plaintext

# Copyright 2006-2021 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 3 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, see <http://www.gnu.org/licenses/>.
# Tests for rvalue reference parameters of types and their subtypes in GDB,
# based on gdb.cp/ref-params.exp.
if {[skip_cplus_tests]} { continue }
standard_testfile .cc
if {[prepare_for_testing $testfile.exp $testfile $srcfile \
{debug c++ additional_flags="-std=gnu++11"}] == -1} {
return -1
}
proc gdb_start_again {text prefix} {
global binfile
global srcfile
with_test_prefix $prefix {
clean_restart $binfile
runto ${srcfile}:[gdb_get_line_number $text]
}
}
set t "print value of f1 on (Child&&) in main"
gdb_start_again "marker1 here" $t
gdb_test "print f1(static_cast<Child&&>(Q))" ".* = 40.*" $t
gdb_test "print f3(static_cast<int&&> (global_int))" " = 8"
gdb_test "print f4(static_cast<float&&> (global_float))" " = 3"
gdb_test "print static_cast<int&> (global_int)" " = \\(int &\\) @$hex: 7"
gdb_test "print static_cast<int&&> (global_int)" " = \\(int &&\\) @$hex: 7"
gdb_test "print static_cast<float&> (global_float)" " = \\(float &\\) @$hex: 3\\.$decimal"
gdb_test "print static_cast<float&&> (global_float)" " = \\(float &&\\) @$hex: 3\\.$decimal"
set t "print value of f2 on (Child&&) in main"
gdb_start_again "marker1 here" $t
gdb_test "print f2(static_cast<Child&&>(Q))" ".* = 40.*" $t
set t "print value of Child&& in f2"
gdb_start_again "marker2 here" $t
gdb_test "print C" ".*id = 42.*" $t
gdb_test "print f1 (static_cast<Child&&> (C))" ".* = 42.*" \
"print value of f1 on Child&& in f2"
set t "print value of Parent&& in f1"
gdb_start_again "marker3 here" $t
gdb_test "print R" ".*id = 41.*" $t
set t "print f1(static_cast<MultiChild&&>(MQ))"
gdb_start_again "breakpoint MQ here" $t
gdb_test $t ".* = 53"
set t "print mf1(static_cast<MultiChild&&>(MQ))"
gdb_start_again "breakpoint MQ here" $t
gdb_test $t ".* = 106"
set t "print mf2(static_cast<MultiChild&&>(MQ))"
gdb_start_again "breakpoint MQ here" $t
gdb_test $t ".* = 106"