Fix casting in-memory values of primitive types to const reference

It's currently not possible to cast an in-memory value of a primitive
type to const reference:
```
(gdb) p Q.id
$1 = 42
(gdb) p (int&)Q.id
$2 = (int &) @0x22fd0c: 42
(gdb) p (const int&)Q.id
Attempt to take address of value not located in memory.
```

And if in a function call an argument needs the same kind of casting,
it also doesn't work:
```
(gdb) l f3
39      int f3(const int &i)
40      {
41        return i;
42      }
(gdb) p f3(Q.id)
Attempt to take address of value not located in memory.
```

It's because when the constness of the type changes in a call to
value_cast, a new not_lval value is allocated, which doesn't exist
in the target memory.

Fixed by ignoring const/volatile/restrict qualifications in
value_cast when comparing cast type to original type, so the new
value will point to the same location as the original value:
```
(gdb) p (int&)i
$2 = (int &) @0x39f72c: 1
(gdb) p (const int&)i
$3 = (const int &) @0x39f72c: 1
(gdb) p f3(Q.id)
$4 = 42
```

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19423
Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
Hannes Domani
2024-03-20 18:23:40 +01:00
parent 23cdd9431a
commit d391f3721e
4 changed files with 12 additions and 1 deletions

View File

@@ -180,6 +180,9 @@ gdb_test "print (unsigned long long) (LeftRight *) (Right *) &gd == gd_value" \
gdb_test "print (unsigned long long) (LeftRight *) (Right *) r_value == gd_value" \ gdb_test "print (unsigned long long) (LeftRight *) (Right *) r_value == gd_value" \
" = true" " = true"
gdb_test "print (const int &) gd.left" \
" = \\(const int \\&\\) @$nonzero_hex: 23"
gdb_test "print reinterpret_cast<LeftRight *>(l) == lr_l" " = true" gdb_test "print reinterpret_cast<LeftRight *>(l) == lr_l" " = true"
gdb_test "print reinterpret_cast<LeftRight *>(r) == lr_r" " = true" gdb_test "print reinterpret_cast<LeftRight *>(r) == lr_r" " = true"
gdb_test "print reinterpret_cast<Left *>(lr) == l_lr" " = true" gdb_test "print reinterpret_cast<Left *>(lr) == l_lr" " = true"

View File

@@ -36,6 +36,11 @@ int f2(Child& C)
return f1(C); /* Set breakpoint marker2 here. */ return f1(C); /* Set breakpoint marker2 here. */
} }
int f3(const int &i)
{
return i;
}
struct OtherParent { struct OtherParent {
OtherParent (int other_id0) : other_id(other_id0) { } OtherParent (int other_id0) : other_id(other_id0) { }
int other_id; int other_id;
@@ -64,6 +69,7 @@ int main(void)
f2(Q); f2(Q);
f2(QR); f2(QR);
f3(Q.id);
MultiChild MQ(53); MultiChild MQ(53);
MultiChild& MQR = MQ; MultiChild& MQR = MQ;

View File

@@ -62,3 +62,4 @@ gdb_test "print mf2(MQ)" ".* = 106"
gdb_test "print f1(MQR)" ".* = 53" gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106" gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106" gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"

View File

@@ -411,7 +411,8 @@ value_cast (struct type *type, struct value *arg2)
In this case we want to preserve the LVAL of ARG2 as this allows the 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 resulting value to be used in more places. We do this by calling
VALUE_COPY if appropriate. */ VALUE_COPY if appropriate. */
if (types_deeply_equal (arg2->type (), type)) if (types_deeply_equal (make_unqualified_type (arg2->type ()),
make_unqualified_type (type)))
{ {
/* If the types are exactly equal then we can avoid creating a new /* If the types are exactly equal then we can avoid creating a new
value completely. */ value completely. */