aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2021-03-09 11:11:14 +0000
committerAndrew Burgess <andrew.burgess@embecosm.com>2021-04-07 12:49:12 +0100
commit30ab35866805d5f1251b7f40578ce985dd18d688 (patch)
tree5fb292bf5ccb72f9c38fe3bc96ec6701472036fb /gdb
parent5e18990f1f2957e59fa4b62d64ed0cb683b65b58 (diff)
downloadgdb-30ab35866805d5f1251b7f40578ce985dd18d688.zip
gdb-30ab35866805d5f1251b7f40578ce985dd18d688.tar.gz
gdb-30ab35866805d5f1251b7f40578ce985dd18d688.tar.bz2
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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/testsuite/ChangeLog9
-rw-r--r--gdb/testsuite/gdb.cp/rvalue-ref-params.cc19
-rw-r--r--gdb/testsuite/gdb.cp/rvalue-ref-params.exp9
-rw-r--r--gdb/valops.c21
5 files changed, 61 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d8b3313..072fa09 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
2021-04-07 Andrew Burgess <andrew.burgess@embecosm.com>
+ * valops.c (value_cast): Call value_deeply_equal before performing
+ any cast.
+
+2021-04-07 Andrew Burgess <andrew.burgess@embecosm.com>
+
* gdbtypes.c (types_equal): Move pointer equality check earlier in
the function.
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c9c6063..0a081fc 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,14 @@
2021-04-07 Andrew Burgess <andrew.burgess@embecosm.com>
+ * 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 Andrew Burgess <andrew.burgess@embecosm.com>
+
* gdb.dwarf2/fission-relative-dwo.c: New file.
* gdb.dwarf2/fission-relative-dwo.exp: New file.
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-params.cc b/gdb/testsuite/gdb.cp/rvalue-ref-params.cc
index d38c96c..d6340fa 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-params.cc
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-params.cc
@@ -42,6 +42,18 @@ f2 (Child &&C)
return f1 (std::move (C)); /* Set breakpoint marker2 here. */
}
+int
+f3 (int &&var_i)
+{
+ return var_i + 1;
+}
+
+int
+f4 (float &&var_f)
+{
+ return static_cast <int> (var_f);
+}
+
struct OtherParent
{
OtherParent (int other_id0) : other_id (other_id0) { }
@@ -65,6 +77,10 @@ mf2 (MultiChild &&C)
return mf1 (std::move (C));
}
+/* These are used from within GDB. */
+int global_int = 7;
+float global_float = 3.5f;
+
int
main ()
{
@@ -81,5 +97,8 @@ main ()
mf2 (std::move (MQ)); /* Set breakpoint MQ here. */
+ (void) f3 (-1);
+ (void) f4 (3.5);
+
return 0;
}
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-params.exp b/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
index 53bd065..1fd3edb 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
@@ -40,6 +40,15 @@ 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
diff --git a/gdb/valops.c b/gdb/valops.c
index b65401c..8694c12 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -415,8 +415,25 @@ value_cast (struct type *type, struct value *arg2)
int convert_to_boolean = 0;
- if (value_type (arg2) == type)
- return arg2;
+ /* TYPE might be equal in meaning to the existing type of ARG2, but for
+ many reasons, might be a different type object (e.g. TYPE might be a
+ gdbarch owned type, while VALUE_TYPE (ARG2) could be an objfile owned
+ type).
+
+ In this case we want to preserve the LVAL of ARG2 as this allows the
+ resulting value to be used in more places. We do this by calling
+ VALUE_COPY if appropriate. */
+ if (types_deeply_equal (value_type (arg2), type))
+ {
+ /* If the types are exactly equal then we can avoid creating a new
+ value completely. */
+ if (value_type (arg2) != type)
+ {
+ arg2 = value_copy (arg2);
+ deprecated_set_value_type (arg2, type);
+ }
+ return arg2;
+ }
if (is_fixed_point_type (type))
return value_cast_to_fixed_point (type, arg2);