* [PATCH] infcall: Add support for integer literals as reference function paramters
@ 2025-10-16 15:48 Keith Seitz
2025-10-17 14:49 ` Tom Tromey
` (4 more replies)
0 siblings, 5 replies; 25+ messages in thread
From: Keith Seitz @ 2025-10-16 15:48 UTC (permalink / raw)
To: gdb-patches
This patch attempts to mitigate the shortcomings of passing literals
to inferior function calls requiring references. The specific use case here
is std::map's operator[]:
std::map int_map<int, int>;
int_map[1] = 10;
(gdb) print int_map[1]
Attempt to take address of value not located in memory.
This is occurring because while value_coerce_to_target understands
that some values need to be allocated and copied to the inferior's
memory, it only considers the actual parsed type of the argument value,
ignoring the actual type of the function parameter. That is,
in this specific case, the value's parsed type is TYPE_CODE_INT, but
the function requires TYPE_CODE_REF. We need to account for the
reference.
I've added some tests to start testing string-based maps, e.g.,
std::map<string, int>, but that is quite a bit more complicated to
deal with -- we need to not only allocate memory in the inferior,
we need to initialize the string and its contents. Perhaps this can
be done, but I have not attempted that in this patch.
I uncovered one small hiccup while implementing this change. It
appears that Fortran compilers use a hidden first argument which
is used to pass results from functions back to callers, and these
are implemented behind the scenes as references, marked in the debug
info as DW_TAG_reference. These should not be subject to this logic,
and I have therefore limited this to types defined in C++.
On the plus side, the last remaining failure in c++/15372 is now
fixed, and that bug could be closed.
With this patch, we can now print map entries with integer keys:
(gdb) print int_map[1]
$1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
---
gdb/infcall.c | 2 +-
gdb/testsuite/gdb.cp/ref-params.cc | 78 +++++++++++++-
gdb/testsuite/gdb.cp/ref-params.exp | 106 ++++++++++++++++++-
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
gdb/valops.c | 25 +++--
gdb/value.h | 3 +-
6 files changed, 202 insertions(+), 13 deletions(-)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index c4b4c8f0bea..823a2b96591 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -263,7 +263,7 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
this point, we could allocate arguments on the stack instead of
calling malloc if we knew that their addresses would not be
saved by the called function. */
- arg = value_coerce_to_target (arg);
+ arg = value_coerce_to_target (arg, type);
switch (type->code ())
{
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
index cd53adb834f..827b0a1ccf9 100644
--- a/gdb/testsuite/gdb.cp/ref-params.cc
+++ b/gdb/testsuite/gdb.cp/ref-params.cc
@@ -17,6 +17,9 @@
/* Author: Paul N. Hilfinger, AdaCore Inc. */
+#include <map>
+#include <string>
+
struct Parent {
Parent (int id0) : id(id0) { }
int id;
@@ -60,7 +63,53 @@ int mf2(MultiChild& C)
return mf1(C);
}
-int main(void)
+/* For C++/25957 (const reference parameters and std::map operator[]). */
+std::map<int, int> int_map;
+std::map<std::string, int> string_map;
+int global_int_key = 42;
+std::string global_string_key = "test";
+
+/* Helper functions to test reference parameter behavior. */
+int
+const_ref_func (const int &x)
+{
+ return x * 2;
+}
+
+int
+ref_func (int &x)
+{
+ x++;
+ return x;
+}
+
+std::string
+const_string_ref_func (const std::string &s)
+{
+ return s + "_modified";
+}
+
+class TestClass
+{
+public:
+ int value;
+
+ TestClass (int v) : value (v) {}
+
+ int
+ const_ref_method (const int &x) const
+ {
+ return value + x;
+ }
+
+ int
+ ref_method (int &x)
+ {
+ return value + 2 * x;
+ }
+};
+
+int main(void)
{
Child Q(42);
Child& QR = Q;
@@ -76,5 +125,30 @@ int main(void)
mf2(MQ); /* Set breakpoint MQ here. */
- return 0;
+ /* c++/25957 test setup - Initialize maps with some data. */
+ int_map[1] = 10;
+ int_map[2] = 20;
+ int_map[global_int_key] = 100;
+
+ string_map["hello"] = 1;
+ string_map["world"] = 2;
+ string_map[global_string_key] = 99;
+
+ TestClass obj (5);
+ int local_var = 15;
+
+ /* Prevent compiler from optimizing away the method calls. */
+ (void) int_map.size ();
+ (void) int_map.empty ();
+ (void) int_map.find (1);
+ (void) int_map.count (1);
+ int dummy_int = 99;
+ (void) const_ref_func (dummy_int);
+ (void) ref_func (dummy_int);
+ (void) const_string_ref_func (global_string_key);
+ (void) obj.const_ref_method (dummy_int);
+ (void) obj.ref_method (dummy_int);
+
+ /* Breakpoint here for c++/25957 testing. */
+ return 0; /* breakpoint-here */
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
index 4f2cbb5dace..b1b7ef93317 100644
--- a/gdb/testsuite/gdb.cp/ref-params.exp
+++ b/gdb/testsuite/gdb.cp/ref-params.exp
@@ -24,7 +24,7 @@ require allow_cplus_tests
standard_testfile .cc
-if {[build_executable $testfile.exp $testfile $srcfile {debug c++}] == -1} {
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} {
return -1
}
@@ -63,3 +63,107 @@ gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"
+
+# Inferior function call tests which have reference arguments.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
+gdb_start_again "breakpoint-here"
+
+# Test accessing existing map elements
+gdb_test "print int_map\[1\]" ": 10" \
+ "access existing map element with literal key"
+
+gdb_test "print int_map\[global_int_key\]" ": 100" \
+ "access existing map element with variable key"
+
+# Test accessing non-existing elements with literals
+gdb_test "print int_map\[99\]" \
+ ": 0" \
+ "attempt to access non-existing map element with literal" \
+
+# Test using operator[] syntax explicitly
+gdb_test "print int_map.operator\[\]\(1\)" \
+ ": 10" \
+ "explicit operator[] call with literal"
+
+# Test with string maps
+setup_xfail c++/25957 *-*-*
+gdb_test "print string_map\[\"hello\"\]" \
+ ": 1" \
+ "string map access with literal string"
+
+gdb_test "print string_map\[global_string_key\]" \
+ ": 99" \
+ "string map access with variable string"
+
+# Test calling function with const reference parameter and literal
+gdb_test "print const_ref_func(10)" \
+ "= 20" \
+ "call function with const ref param and literal"
+
+# Test calling function with const reference parameter and variable
+gdb_test "print const_ref_func(global_int_key)" \
+ "= 84" \
+ "call function with const ref param and variable"
+
+# Test with local variable
+gdb_test "print const_ref_func(local_var)" \
+ "= 30" \
+ "call function with const ref param and local var"
+
+# Test string const reference
+setup_xfail c++/25957 *-*-*
+gdb_test "print const_string_ref_func(\"test\")" \
+ {= "test_modified"} \
+ "call function with const string ref and literal"
+
+# Test calling function with non-const reference parameter.
+# This should work with variables but not literals.
+gdb_test "print ref_func(global_int_key)" \
+ " = 43" \
+ "call function with non-const ref param and variable"
+
+gdb_test "print ref_func(local_var)" \
+ " = 16" \
+ "call function with non-const ref param and local var"
+
+# This should fail: literals can't be non-const refs.
+gdb_test "print ref_func(10)" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with non-const ref param and literal"
+
+gdb_test "print obj.const_ref_method(5)" \
+ "= 10" \
+ "call const method with const ref param and literal"
+
+gdb_test "print obj.const_ref_method(local_var)" \
+ "= 20" \
+ "call const method with const ref param and variable"
+
+gdb_test "print obj.ref_method(local_var)" \
+ " = 35" \
+ "call method with non-const ref param and variable"
+
+# Test potential workarounds
+gdb_test_no_output {set $temp_key = 99} "create temporary variable"
+gdb_test_no_output {set var int_map[$temp_key] = 1234}
+gdb_test {print int_map[$temp_key]} \
+ ": 1234" \
+ "map access with convenience variable"
+
+gdb_test "print int_map.size()" " = 4"
+
+gdb_test "print int_map.empty()" " = false"
+
+gdb_test "print int_map.find(1)" " = {.*}"
+
+gdb_test "print int_map.count(1)" " = 1"
+
+gdb_test "print int_map.count(1234)" "= 0"
+
+gdb_test "whatis const_ref_func" \
+ {type = int \(const int &\)} \
+ "show function signature with const reference"
+
+gdb_test "whatis ref_func" \
+ {type = int \(int &\)} \
+ "show function signature with reference"
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index f4d55be92ef..8d8fe0bee99 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
gdb_test "print f (ci)" "2" "lvalue reference to const overload"
-setup_kfail "c++/15372" "*-*-*"
gdb_test "print f (3)" "3" "rvalue reference overload"
gdb_test "print g (i)" \
diff --git a/gdb/valops.c b/gdb/valops.c
index fa87546770a..78f411f7211 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1464,18 +1464,29 @@ value_must_coerce_to_target (struct value *val)
storage, and this function copies them to the target. */
struct value *
-value_coerce_to_target (struct value *val)
+value_coerce_to_target (struct value *val, struct type *param_type)
{
LONGEST length;
CORE_ADDR addr;
- if (!value_must_coerce_to_target (val))
- return val;
+ if (param_type != nullptr && param_type->language () == language_cplus
+ && TYPE_IS_REFERENCE (param_type))
+ {
+ length = check_typedef (val->type ())->length ();
+ addr = allocate_space_in_inferior (length);
+ write_memory (addr, val->contents ().data (), length);
+ return value_ref (value_at_lazy (val->type (), addr),
+ param_type->code ());
+ }
+ else if (value_must_coerce_to_target (val))
+ {
+ length = check_typedef (val->type ())->length ();
+ addr = allocate_space_in_inferior (length);
+ write_memory (addr, val->contents ().data (), length);
+ return value_at_lazy (val->type (), addr);
+ }
- length = check_typedef (val->type ())->length ();
- addr = allocate_space_in_inferior (length);
- write_memory (addr, val->contents ().data (), length);
- return value_at_lazy (val->type (), addr);
+ return val;
}
/* Given a value which is an array, return a value which is a pointer
diff --git a/gdb/value.h b/gdb/value.h
index b9d2809bead..eecfc729714 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1278,7 +1278,8 @@ extern LONGEST value_ptrdiff (struct value *arg1, struct value *arg2);
extern bool value_must_coerce_to_target (struct value *arg1);
-extern struct value *value_coerce_to_target (struct value *arg1);
+extern struct value *value_coerce_to_target (struct value *arg1,
+ struct type *param_type = nullptr);
extern struct value *value_coerce_array (struct value *arg1);
base-commit: b6753354fbbe7c2c66ae9f452ba7aa049db0fe0c
--
2.51.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] infcall: Add support for integer literals as reference function paramters
2025-10-16 15:48 [PATCH] infcall: Add support for integer literals as reference function paramters Keith Seitz
@ 2025-10-17 14:49 ` Tom Tromey
2025-10-20 19:00 ` Keith Seitz
2025-10-20 19:36 ` [PATCH v2] " Keith Seitz
` (3 subsequent siblings)
4 siblings, 1 reply; 25+ messages in thread
From: Tom Tromey @ 2025-10-17 14:49 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> This patch attempts to mitigate the shortcomings of passing literals
Keith> to inferior function calls requiring references. The specific use case here
Keith> is std::map's operator[]:
Keith> (gdb) print int_map[1]
Keith> Attempt to take address of value not located in memory.
I didn't see in the text or the patch what the method type really is.
Keith> +#include <map>
Keith> +#include <string>
It's better for tests not to use libstdc++ stuff if possible, and to
just write out a method with the problem signature in a locally-defined
type.
Keith> -if {[build_executable $testfile.exp $testfile $srcfile {debug c++}] == -1} {
Keith> +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} {
This results in starting an extra gdb that is immediately exited.
Tom
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] infcall: Add support for integer literals as reference function paramters
2025-10-17 14:49 ` Tom Tromey
@ 2025-10-20 19:00 ` Keith Seitz
0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2025-10-20 19:00 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Hi, Tom,
On 10/17/25 7:49 AM, Tom Tromey wrote:
>>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
>
> Keith> This patch attempts to mitigate the shortcomings of passing literals
> Keith> to inferior function calls requiring references. The specific use case here
> Keith> is std::map's operator[]:
>
> Keith> (gdb) print int_map[1]
> Keith> Attempt to take address of value not located in memory.
>
> I didn't see in the text or the patch what the method type really is.
I believe I have addressed this in upcoming v2.
> Keith> +#include <map>
> Keith> +#include <string>
>
> It's better for tests not to use libstdc++ stuff if possible, and to
> just write out a method with the problem signature in a locally-defined
> type.
Gotcha. I have removed all the offending libstdc++ classes and rewritten
using just basic function/method calls.
> Keith> -if {[build_executable $testfile.exp $testfile $srcfile {debug c++}] == -1} {
> Keith> +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} {
>
> This results in starting an extra gdb that is immediately exited.
Reverted.
Thank you for the review.
Keith
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2] infcall: Add support for integer literals as reference function paramters
2025-10-16 15:48 [PATCH] infcall: Add support for integer literals as reference function paramters Keith Seitz
2025-10-17 14:49 ` Tom Tromey
@ 2025-10-20 19:36 ` Keith Seitz
2025-10-21 20:19 ` Tom Tromey
2026-01-27 19:01 ` [PATCH v4] " Keith Seitz
` (2 subsequent siblings)
4 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2025-10-20 19:36 UTC (permalink / raw)
To: gdb-patches
This patch attempts to mitigate the shortcomings of passing literals
to inferior function calls requiring references. The specific use case here
is std::map's operator[]:
std::map int_map<int, int>;
int_map[1] = 10;
(gdb) print int_map[1]
Attempt to take address of value not located in memory.
This is occurring because while value_coerce_to_target understands
that some values need to be allocated and copied to the inferior's
memory, it only considers the actual parsed type of the argument value,
ignoring the actual type of the function parameter. That is,
in this specific case, the value's parsed type is TYPE_CODE_INT, but
the function requires TYPE_CODE_REF. We need to account for the
reference.
I uncovered one small hiccup while implementing this change. It
appears that Fortran compilers use a hidden first argument which
is used to pass results from functions back to callers, and these
are implemented behind the scenes as references, marked in the debug
info as DW_TAG_reference. These should not be subject to this logic,
and I have therefore limited this to types defined in C++.
On the plus side, the last remaining failure in c++/15372 is now
fixed, and that bug could be closed.
With this patch, we can now print map entries with integer keys:
(gdb) print int_map[1]
$1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
---
gdb/infcall.c | 2 +-
gdb/testsuite/gdb.cp/ref-params.cc | 97 ++++++++++++++-
gdb/testsuite/gdb.cp/ref-params.exp | 122 +++++++++++++++++++
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
gdb/valops.c | 25 ++--
gdb/value.h | 3 +-
6 files changed, 238 insertions(+), 12 deletions(-)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index c4b4c8f0bea..823a2b96591 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -263,7 +263,7 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
this point, we could allocate arguments on the stack instead of
calling malloc if we knew that their addresses would not be
saved by the called function. */
- arg = value_coerce_to_target (arg);
+ arg = value_coerce_to_target (arg, type);
switch (type->code ())
{
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
index cd53adb834f..ea3e14302eb 100644
--- a/gdb/testsuite/gdb.cp/ref-params.cc
+++ b/gdb/testsuite/gdb.cp/ref-params.cc
@@ -60,7 +60,69 @@ int mf2(MultiChild& C)
return mf1(C);
}
-int main(void)
+/* A class to be used by functions and methods exercising c++/25957. */
+class TestClass
+{
+ public:
+ int value;
+
+ TestClass (int v) : value (v) {}
+
+ int
+ const_ref_method (const int &x) const
+ {
+ return value + x;
+ }
+
+ int
+ const_ref_method (const TestClass &obj) const
+ {
+ return value + obj.value;
+ }
+
+ int
+ ref_method (int &x)
+ {
+ return value + 2 * x;
+ }
+
+ int
+ ref_method (TestClass &obj)
+ {
+ return value + 2 * obj.value;
+ }
+};
+
+/* Define globals to be used by functions and methods exercising c++/25957. */
+int global_int = 42;
+TestClass global_obj (10);
+
+/* Helper functions to test reference parameter behavior for c++/25957. */
+int
+const_ref_func (const int &x)
+{
+ return x * 2;
+}
+
+int
+const_ref_func (const TestClass &obj)
+{
+ return obj.value * 2;
+}
+
+int
+ref_func (int &x)
+{
+ return x + 1;
+}
+
+int
+ref_func (TestClass &obj)
+{
+ return obj.value + 1;
+}
+
+int main(void)
{
Child Q(42);
Child& QR = Q;
@@ -76,5 +138,36 @@ int main(void)
mf2(MQ); /* Set breakpoint MQ here. */
- return 0;
+ TestClass obj (5);
+ int local_var = 15;
+
+ /* Prevent compiler from optimizing away the function and method calls. */
+ int dummy_int = 99;
+ (void) const_ref_func (dummy_int);
+ (void) const_ref_func (global_int);
+ (void) const_ref_func (obj);
+ (void) const_ref_func (global_obj);
+ (void) ref_func (dummy_int);
+ (void) ref_func (global_int);
+ (void) ref_func (obj);
+ (void) ref_func (global_obj);
+ (void) obj.const_ref_method (dummy_int);
+ (void) obj.const_ref_method (global_int);
+ (void) obj.const_ref_method (obj);
+ (void) obj.const_ref_method (global_obj);
+ (void) obj.ref_method (dummy_int);
+ (void) obj.ref_method (global_int);
+ (void) obj.ref_method (obj);
+ (void) obj.ref_method (global_obj);
+ (void) global_obj.const_ref_method (dummy_int);
+ (void) global_obj.const_ref_method (global_int);
+ (void) global_obj.const_ref_method (obj);
+ (void) global_obj.const_ref_method (global_obj);
+ (void) global_obj.ref_method (dummy_int);
+ (void) global_obj.ref_method (global_int);
+ (void) global_obj.ref_method (obj);
+ (void) global_obj.ref_method (global_obj);
+
+ /* Breakpoint here for c++/25957 testing. */
+ return 0; /* breakpoint-here */
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
index 4f2cbb5dace..96571963140 100644
--- a/gdb/testsuite/gdb.cp/ref-params.exp
+++ b/gdb/testsuite/gdb.cp/ref-params.exp
@@ -63,3 +63,125 @@ gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"
+
+# Inferior function call tests which have reference arguments.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
+gdb_start_again "breakpoint-here"
+
+# Test functions taking const reference parameter.
+gdb_test "print const_ref_func(10)" \
+ "= 20" \
+ "call function with const ref param and literal"
+
+gdb_test "print const_ref_func(global_int)" \
+ "= 84" \
+ "call function with const ref param and global variable"
+
+gdb_test "print const_ref_func(local_var)" \
+ "= 30" \
+ "call function with const ref param and local variable"
+
+gdb_test "print const_ref_func(obj)" \
+ "= 10" \
+ "call function with const ref param and object"
+
+gdb_test "print const_ref_func(global_obj)" \
+ "= 20" \
+ "call function with const ref param and global object"
+
+# Test functions taking non-const reference parameter.
+gdb_test "print ref_func(10)" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with non-const ref param and literal"
+
+gdb_test "print ref_func(global_int)" \
+ " = 43" \
+ "call function with non-const ref param and global variable"
+
+gdb_test "print ref_func(local_var)" \
+ " = 16" \
+ "call function with non-const ref param and local variable"
+
+gdb_test "print ref_func(obj)" \
+ "= 6" \
+ "call function with non-const ref param and object"
+
+gdb_test "print ref_func(global_obj)" \
+ "= 11" \
+ "call function with non-const ref param and global object"
+
+# Test methods taking constant reference parameter.
+gdb_test "print obj.const_ref_method(5)" \
+ "= 10" \
+ "call const method with const ref param and literal"
+
+gdb_test "print obj.const_ref_method(global_int)" \
+ "= 47" \
+ "call const method with const ref param and global variable"
+
+gdb_test "print obj.const_ref_method(local_var)" \
+ "= 20" \
+ "call const method with const ref param and local variable"
+
+gdb_test "print obj.const_ref_method (obj)" \
+ "= 10" \
+ "call method with const ref param and object"
+
+# Test methods taking non-const reference parameters.
+gdb_test "print obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal"
+
+gdb_test "print obj.ref_method(global_int)" \
+ "= 89" \
+ "cal method with non-const ref param and global variable"
+
+gdb_test "print obj.ref_method(local_var)" \
+ " = 35" \
+ "call method with non-const ref param and local variable"
+
+gdb_test "print obj.ref_method(obj)" \
+ "= 15" \
+ "call method with non-const ref param and object"
+
+# Test global_obj methods taking constant reference parameter.
+gdb_test "print global_obj.const_ref_method(5)" \
+ "= 15" \
+ "call global const method with const ref param and literal"
+
+gdb_test "print global_obj.const_ref_method(global_int)" \
+ "= 52" \
+ "call global const method with const ref param and global variable"
+
+gdb_test "print global_obj.const_ref_method(local_var)" \
+ "= 25" \
+ "call global const method with const ref param and local variable"
+
+gdb_test "print global_obj.const_ref_method(obj)" \
+ "= 15" \
+ "call global method with const ref param and object"
+
+gdb_test "print global_obj.const_ref_method(global_obj)" \
+ "= 20" \
+ "call global method with const ref param and global object"
+
+# Test global_obj methods taking non-const reference parameters.
+gdb_test "print global_obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal"
+
+gdb_test "print global_obj.ref_method(global_int)" \
+ "= 94" \
+ "call global method with non-const ref param and global variable"
+
+gdb_test "print global_obj.ref_method(local_var)" \
+ "= 40" \
+ "call global method with non-const ref param and local variable"
+
+gdb_test "print global_obj.ref_method(obj)" \
+ "= 20" \
+ "call global method with non-const ref param and object"
+
+gdb_test "print global_obj.ref_method(global_obj)" \
+ "= 30" \
+ "call global method with non-const ref param and global object"
\ No newline at end of file
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index f4d55be92ef..8d8fe0bee99 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
gdb_test "print f (ci)" "2" "lvalue reference to const overload"
-setup_kfail "c++/15372" "*-*-*"
gdb_test "print f (3)" "3" "rvalue reference overload"
gdb_test "print g (i)" \
diff --git a/gdb/valops.c b/gdb/valops.c
index fa87546770a..78f411f7211 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1464,18 +1464,29 @@ value_must_coerce_to_target (struct value *val)
storage, and this function copies them to the target. */
struct value *
-value_coerce_to_target (struct value *val)
+value_coerce_to_target (struct value *val, struct type *param_type)
{
LONGEST length;
CORE_ADDR addr;
- if (!value_must_coerce_to_target (val))
- return val;
+ if (param_type != nullptr && param_type->language () == language_cplus
+ && TYPE_IS_REFERENCE (param_type))
+ {
+ length = check_typedef (val->type ())->length ();
+ addr = allocate_space_in_inferior (length);
+ write_memory (addr, val->contents ().data (), length);
+ return value_ref (value_at_lazy (val->type (), addr),
+ param_type->code ());
+ }
+ else if (value_must_coerce_to_target (val))
+ {
+ length = check_typedef (val->type ())->length ();
+ addr = allocate_space_in_inferior (length);
+ write_memory (addr, val->contents ().data (), length);
+ return value_at_lazy (val->type (), addr);
+ }
- length = check_typedef (val->type ())->length ();
- addr = allocate_space_in_inferior (length);
- write_memory (addr, val->contents ().data (), length);
- return value_at_lazy (val->type (), addr);
+ return val;
}
/* Given a value which is an array, return a value which is a pointer
diff --git a/gdb/value.h b/gdb/value.h
index b9d2809bead..eecfc729714 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1278,7 +1278,8 @@ extern LONGEST value_ptrdiff (struct value *arg1, struct value *arg2);
extern bool value_must_coerce_to_target (struct value *arg1);
-extern struct value *value_coerce_to_target (struct value *arg1);
+extern struct value *value_coerce_to_target (struct value *arg1,
+ struct type *param_type = nullptr);
extern struct value *value_coerce_array (struct value *arg1);
base-commit: 2c3d37c44b70a6e45a43045fcf07e8e739573c49
--
2.51.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] infcall: Add support for integer literals as reference function paramters
2025-10-20 19:36 ` [PATCH v2] " Keith Seitz
@ 2025-10-21 20:19 ` Tom Tromey
2025-10-22 12:05 ` Andrew Burgess
0 siblings, 1 reply; 25+ messages in thread
From: Tom Tromey @ 2025-10-21 20:19 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> This patch attempts to mitigate the shortcomings of passing literals
Keith> to inferior function calls requiring references. The specific use case here
Keith> is std::map's operator[]:
Thanks for doing this.
Keith> struct value *
Keith> -value_coerce_to_target (struct value *val)
Keith> +value_coerce_to_target (struct value *val, struct type *param_type)
Keith> {
I wasn't totally sold on doing the work here and not in value_arg_coerce
but I guess it makes sense.
Keith> + if (param_type != nullptr && param_type->language () == language_cplus
Keith> + && TYPE_IS_REFERENCE (param_type))
Keith> + {
Can we get here with a value that has an address, and so we don't need
to make a copy? Like if there's a local variable 'x', and you do 'print
map[x]'?
If the argument is already in memory, then just casting its address to a
reference would be a lot better, especially because memcpy()ing the data
into the inferior is only really correct for trivially-copyable types.
I don't know if that property (trivially-copyable) is all that easy to
detect in gdb, but if it is, I guess it would make sense to detect it
and throw an exception. Since in that case we'd be looking at something
like a callee that wants memory but where the object has been SROA'd or
something along those lines.
Tom
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] infcall: Add support for integer literals as reference function paramters
2025-10-21 20:19 ` Tom Tromey
@ 2025-10-22 12:05 ` Andrew Burgess
2025-10-22 13:21 ` Tom Tromey
2026-01-22 19:05 ` Keith Seitz
0 siblings, 2 replies; 25+ messages in thread
From: Andrew Burgess @ 2025-10-22 12:05 UTC (permalink / raw)
To: Tom Tromey, Keith Seitz; +Cc: gdb-patches
Tom Tromey <tom@tromey.com> writes:
>>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
>
> Keith> This patch attempts to mitigate the shortcomings of passing literals
> Keith> to inferior function calls requiring references. The specific use case here
> Keith> is std::map's operator[]:
>
> Thanks for doing this.
>
> Keith> struct value *
> Keith> -value_coerce_to_target (struct value *val)
> Keith> +value_coerce_to_target (struct value *val, struct type *param_type)
> Keith> {
>
> I wasn't totally sold on doing the work here and not in value_arg_coerce
> but I guess it makes sense.
>
> Keith> + if (param_type != nullptr && param_type->language () == language_cplus
> Keith> + && TYPE_IS_REFERENCE (param_type))
> Keith> + {
>
> Can we get here with a value that has an address, and so we don't need
> to make a copy? Like if there's a local variable 'x', and you do 'print
> map[x]'?
I took a look at this patch too, and came here to say the same thing.
In fact, this is exactly why the 'param_type->language () ==
language_cplus' is needed. The Fortran breakage that Keith mentions
does this:
(gdb) p return_string(returned_string_debugger, 40)
(gdb) p returned_string_debugger
The first line calls 'return_string' passing in the inferior variable
'returned_string_debugger' (length 40), the function is then going to
fill that variable in for us, which we print on the next line.
Without the 'param_type->language() == language_cplus' bit, we end up
creating a copy of 'returned_string_debugger' in the inferior, which the
'return_string' function fills in. Then back in GDB we try to print the
original variable, which _hasn't_ been filled in.
This is all just a long way around of saying that Tom's right.
> If the argument is already in memory, then just casting its address to a
> reference would be a lot better, especially because memcpy()ing the data
> into the inferior is only really correct for trivially-copyable types.
I agree with this.
This function `value_coerce_to_target` does seem like a sensible place
to update to fix this, but given that the forcing seems to be entangled
with the parameter type, I wonder if this should be fixed back in
`value_arg_coerce` (infcall.c)? Specifically, in this block:
case TYPE_CODE_REF:
case TYPE_CODE_RVALUE_REF:
{
struct value *new_value;
if (TYPE_IS_REFERENCE (arg_type))
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
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 (), arg);
new_value = value_ref (new_value, type->code ());
return new_value;
}
The comment seems (to me) to hint at the exact problem that you are
trying to solve here. Maybe the solution is to split
`value_coerce_to_target` and `value_must_coerce_to_target` into some
smaller pieces and then reuse those within `value_arg_coerce`?
> I don't know if that property (trivially-copyable) is all that easy to
> detect in gdb, but if it is, I guess it would make sense to detect it
> and throw an exception. Since in that case we'd be looking at something
> like a callee that wants memory but where the object has been SROA'd or
> something along those lines.
We have `language_pass_by_reference`, the return value of which will, I
think, tell you if a type is trivially-copyable or not. I don't think
this is going to be the common path though; don't objects that are not
trivially-copyable have to live in memory? I'm sure there might be some
edge case here, but for me, I'd be happy with a patch that ignores this
for now, and we can come back to this later if/when we find a
problematic case.
Thanks,
Andrew
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] infcall: Add support for integer literals as reference function paramters
2025-10-22 12:05 ` Andrew Burgess
@ 2025-10-22 13:21 ` Tom Tromey
2026-01-22 19:05 ` Keith Seitz
1 sibling, 0 replies; 25+ messages in thread
From: Tom Tromey @ 2025-10-22 13:21 UTC (permalink / raw)
To: Andrew Burgess; +Cc: Tom Tromey, Keith Seitz, gdb-patches
>>>>> "Andrew" == Andrew Burgess <aburgess@redhat.com> writes:
>> I don't know if that property (trivially-copyable) is all that easy to
>> detect in gdb, but if it is, I guess it would make sense to detect it
>> and throw an exception. Since in that case we'd be looking at something
>> like a callee that wants memory but where the object has been SROA'd or
>> something along those lines.
Andrew> We have `language_pass_by_reference`, the return value of which will, I
Andrew> think, tell you if a type is trivially-copyable or not. I don't think
Andrew> this is going to be the common path though; don't objects that are not
Andrew> trivially-copyable have to live in memory? I'm sure there might be some
Andrew> edge case here, but for me, I'd be happy with a patch that ignores this
Andrew> for now, and we can come back to this later if/when we find a
Andrew> problematic case.
Yeah, that seems sensible.
I don't really know if compilers are capable of doing weird stuff like
scalar replacement of a non-trivially-destructible object combined with
inlining of the destructor the avoid needing the object in one piece.
Tom
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2] infcall: Add support for integer literals as reference function paramters
2025-10-22 12:05 ` Andrew Burgess
2025-10-22 13:21 ` Tom Tromey
@ 2026-01-22 19:05 ` Keith Seitz
2026-01-23 14:07 ` Aktemur, Tankut Baris
1 sibling, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2026-01-22 19:05 UTC (permalink / raw)
To: gdb-patches
This patch attempts to mitigate the shortcomings of passing literals
to inferior function calls requiring references. The specific use case here
is std::map's operator[]:
std::map int_map<int, int>;
int_map[1] = 10;
(gdb) print int_map[1]
Attempt to take address of value not located in memory.
This is occurring because while value_coerce_to_target understands
that some values need to be allocated and copied to the inferior's
memory, it only considers the actual parsed type of the argument value,
ignoring the actual type of the function parameter. That is,
in this specific case, the value's parsed type is TYPE_CODE_INT, but
the function requires TYPE_CODE_REF. We need to account for the
reference.
In value_arg_coerce, we have special handling for references, but it
has not specifically dealt with this case. It now checks if the
reference is in memory, and if it isn't, it copies it, if the type
is trivially copyable.
As a result of this patch, the last remaining failure in c++/15372 is now
fixed, and that bug can be closed.
With this patch, we can now print map entries with integer keys:
(gdb) print int_map[1]
$1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
Changes in v2
- Move logic to value_arg_coerce
- Add some attempt to limit copying to trivially copyable types
---
gdb/infcall.c | 19 ++-
gdb/testsuite/gdb.cp/ref-params.cc | 95 ++++++++++++++-
gdb/testsuite/gdb.cp/ref-params.exp | 122 +++++++++++++++++++
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
4 files changed, 232 insertions(+), 5 deletions(-)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index dcbae679d07..b836a868d15 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -276,10 +276,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
- if the value was not previously in memory - in some cases
- we should clearly be allowing this, but how? */
+ convert it back to a reference. For C++ reference parameters,
+ if the value is not already in memory (e.g., a literal), we
+ need to allocate space in the inferior and copy the value there.
+ If the value is already in memory, we can use its address
+ directly. */
new_value = value_cast (type->target_type (), arg);
+ if (new_value->lval () != lval_memory
+ && language_pass_by_reference (new_value->type ())
+ .trivially_copyable)
+ {
+ LONGEST length = check_typedef (new_value->type ())->length ();
+ struct value *addr_val = value_allocate_space_in_inferior (length);
+ CORE_ADDR addr = value_as_address (addr_val);
+ write_memory (addr, new_value->contents ().data (), length);
+ new_value = value_at_lazy (new_value->type (), addr);
+ }
+
new_value = value_ref (new_value, type->code ());
return new_value;
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
index 12e2716b435..3c1aa82396a 100644
--- a/gdb/testsuite/gdb.cp/ref-params.cc
+++ b/gdb/testsuite/gdb.cp/ref-params.cc
@@ -60,6 +60,68 @@ int mf2(MultiChild& C)
return mf1(C);
}
+/* A class to be used by functions and methods exercising c++/25957. */
+class TestClass
+{
+ public:
+ int value;
+
+ TestClass (int v) : value (v) {}
+
+ int
+ const_ref_method (const int &x) const
+ {
+ return value + x;
+ }
+
+ int
+ const_ref_method (const TestClass &obj) const
+ {
+ return value + obj.value;
+ }
+
+ int
+ ref_method (int &x)
+ {
+ return value + 2 * x;
+ }
+
+ int
+ ref_method (TestClass &obj)
+ {
+ return value + 2 * obj.value;
+ }
+};
+
+/* Define globals to be used by functions and methods exercising c++/25957. */
+int global_int = 42;
+TestClass global_obj (10);
+
+/* Helper functions to test reference parameter behavior for c++/25957. */
+int
+const_ref_func (const int &x)
+{
+ return x * 2;
+}
+
+int
+const_ref_func (const TestClass &obj)
+{
+ return obj.value * 2;
+}
+
+int
+ref_func (int &x)
+{
+ return x + 1;
+}
+
+int
+ref_func (TestClass &obj)
+{
+ return obj.value + 1;
+}
+
int main(void)
{
Child Q(42);
@@ -76,5 +138,36 @@ int main(void)
mf2(MQ); /* Set breakpoint MQ here. */
- return 0;
+ TestClass obj (5);
+ int local_var = 15;
+
+ /* Prevent compiler from optimizing away the function and method calls. */
+ int dummy_int = 99;
+ (void) const_ref_func (dummy_int);
+ (void) const_ref_func (global_int);
+ (void) const_ref_func (obj);
+ (void) const_ref_func (global_obj);
+ (void) ref_func (dummy_int);
+ (void) ref_func (global_int);
+ (void) ref_func (obj);
+ (void) ref_func (global_obj);
+ (void) obj.const_ref_method (dummy_int);
+ (void) obj.const_ref_method (global_int);
+ (void) obj.const_ref_method (obj);
+ (void) obj.const_ref_method (global_obj);
+ (void) obj.ref_method (dummy_int);
+ (void) obj.ref_method (global_int);
+ (void) obj.ref_method (obj);
+ (void) obj.ref_method (global_obj);
+ (void) global_obj.const_ref_method (dummy_int);
+ (void) global_obj.const_ref_method (global_int);
+ (void) global_obj.const_ref_method (obj);
+ (void) global_obj.const_ref_method (global_obj);
+ (void) global_obj.ref_method (dummy_int);
+ (void) global_obj.ref_method (global_int);
+ (void) global_obj.ref_method (obj);
+ (void) global_obj.ref_method (global_obj);
+
+ /* Breakpoint here for c++/25957 testing. */
+ return 0; /* breakpoint-here */
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
index b61055e9f50..a94927fae56 100644
--- a/gdb/testsuite/gdb.cp/ref-params.exp
+++ b/gdb/testsuite/gdb.cp/ref-params.exp
@@ -63,3 +63,125 @@ gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"
+
+# Inferior function call tests which have reference arguments.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
+gdb_start_again "breakpoint-here"
+
+# Test functions taking const reference parameter.
+gdb_test "print const_ref_func(10)" \
+ "= 20" \
+ "call function with const ref param and literal"
+
+gdb_test "print const_ref_func(global_int)" \
+ "= 84" \
+ "call function with const ref param and global variable"
+
+gdb_test "print const_ref_func(local_var)" \
+ "= 30" \
+ "call function with const ref param and local variable"
+
+gdb_test "print const_ref_func(obj)" \
+ "= 10" \
+ "call function with const ref param and object"
+
+gdb_test "print const_ref_func(global_obj)" \
+ "= 20" \
+ "call function with const ref param and global object"
+
+# Test functions taking non-const reference parameter.
+gdb_test "print ref_func(10)" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with non-const ref param and literal"
+
+gdb_test "print ref_func(global_int)" \
+ " = 43" \
+ "call function with non-const ref param and global variable"
+
+gdb_test "print ref_func(local_var)" \
+ " = 16" \
+ "call function with non-const ref param and local variable"
+
+gdb_test "print ref_func(obj)" \
+ "= 6" \
+ "call function with non-const ref param and object"
+
+gdb_test "print ref_func(global_obj)" \
+ "= 11" \
+ "call function with non-const ref param and global object"
+
+# Test methods taking constant reference parameter.
+gdb_test "print obj.const_ref_method(5)" \
+ "= 10" \
+ "call const method with const ref param and literal"
+
+gdb_test "print obj.const_ref_method(global_int)" \
+ "= 47" \
+ "call const method with const ref param and global variable"
+
+gdb_test "print obj.const_ref_method(local_var)" \
+ "= 20" \
+ "call const method with const ref param and local variable"
+
+gdb_test "print obj.const_ref_method (obj)" \
+ "= 10" \
+ "call method with const ref param and object"
+
+# Test methods taking non-const reference parameters.
+gdb_test "print obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal"
+
+gdb_test "print obj.ref_method(global_int)" \
+ "= 89" \
+ "cal method with non-const ref param and global variable"
+
+gdb_test "print obj.ref_method(local_var)" \
+ " = 35" \
+ "call method with non-const ref param and local variable"
+
+gdb_test "print obj.ref_method(obj)" \
+ "= 15" \
+ "call method with non-const ref param and object"
+
+# Test global_obj methods taking constant reference parameter.
+gdb_test "print global_obj.const_ref_method(5)" \
+ "= 15" \
+ "call global const method with const ref param and literal"
+
+gdb_test "print global_obj.const_ref_method(global_int)" \
+ "= 52" \
+ "call global const method with const ref param and global variable"
+
+gdb_test "print global_obj.const_ref_method(local_var)" \
+ "= 25" \
+ "call global const method with const ref param and local variable"
+
+gdb_test "print global_obj.const_ref_method(obj)" \
+ "= 15" \
+ "call global method with const ref param and object"
+
+gdb_test "print global_obj.const_ref_method(global_obj)" \
+ "= 20" \
+ "call global method with const ref param and global object"
+
+# Test global_obj methods taking non-const reference parameters.
+gdb_test "print global_obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal"
+
+gdb_test "print global_obj.ref_method(global_int)" \
+ "= 94" \
+ "call global method with non-const ref param and global variable"
+
+gdb_test "print global_obj.ref_method(local_var)" \
+ "= 40" \
+ "call global method with non-const ref param and local variable"
+
+gdb_test "print global_obj.ref_method(obj)" \
+ "= 20" \
+ "call global method with non-const ref param and object"
+
+gdb_test "print global_obj.ref_method(global_obj)" \
+ "= 30" \
+ "call global method with non-const ref param and global object"
\ No newline at end of file
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index bd6933673db..b9da32c244e 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
gdb_test "print f (ci)" "2" "lvalue reference to const overload"
-setup_kfail "c++/15372" "*-*-*"
gdb_test "print f (3)" "3" "rvalue reference overload"
gdb_test "print g (i)" \
base-commit: 01be62d46b2e05e5a994b080974dd3832755e137
--
2.52.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* RE: [PATCH v2] infcall: Add support for integer literals as reference function paramters
2026-01-22 19:05 ` Keith Seitz
@ 2026-01-23 14:07 ` Aktemur, Tankut Baris
2026-01-27 18:43 ` Keith Seitz
0 siblings, 1 reply; 25+ messages in thread
From: Aktemur, Tankut Baris @ 2026-01-23 14:07 UTC (permalink / raw)
To: Keith Seitz, gdb-patches
On Thursday, January 22, 2026 8:06 PM, Keith Seitz wrote:
> This patch attempts to mitigate the shortcomings of passing literals
> to inferior function calls requiring references. The specific use case
> here
> is std::map's operator[]:
>
> std::map int_map<int, int>;
> int_map[1] = 10;
> (gdb) print int_map[1]
> Attempt to take address of value not located in memory.
>
> This is occurring because while value_coerce_to_target understands
> that some values need to be allocated and copied to the inferior's
> memory, it only considers the actual parsed type of the argument value,
> ignoring the actual type of the function parameter. That is,
> in this specific case, the value's parsed type is TYPE_CODE_INT, but
> the function requires TYPE_CODE_REF. We need to account for the
> reference.
>
> In value_arg_coerce, we have special handling for references, but it
> has not specifically dealt with this case. It now checks if the
> reference is in memory, and if it isn't, it copies it, if the type
> is trivially copyable.
>
> As a result of this patch, the last remaining failure in c++/15372 is
> now
> fixed, and that bug can be closed.
>
> With this patch, we can now print map entries with integer keys:
>
> (gdb) print int_map[1]
> $1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int
> const, int> > >::mapped_type &) @0x41f2d4: 10
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
>
> Changes in v2
> - Move logic to value_arg_coerce
> - Add some attempt to limit copying to trivially copyable types
> ---
> gdb/infcall.c | 19 ++-
> gdb/testsuite/gdb.cp/ref-params.cc | 95 ++++++++++++++-
> gdb/testsuite/gdb.cp/ref-params.exp | 122 +++++++++++++++++++
> gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
> 4 files changed, 232 insertions(+), 5 deletions(-)
>
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index dcbae679d07..b836a868d15 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -276,10 +276,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct
> value *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
> - if the value was not previously in memory - in some cases
> - we should clearly be allowing this, but how? */
> + convert it back to a reference. For C++ reference parameters,
> + if the value is not already in memory (e.g., a literal), we
> + need to allocate space in the inferior and copy the value there.
> + If the value is already in memory, we can use its address
> + directly. */
> new_value = value_cast (type->target_type (), arg);
> + if (new_value->lval () != lval_memory
> + && language_pass_by_reference (new_value->type ())
> + .trivially_copyable)
> + {
> + LONGEST length = check_typedef (new_value->type ())->length ();
> + struct value *addr_val = value_allocate_space_in_inferior
> (length);
This uses malloc to allocate the space. I was wondering if allocating
space on the stack wouldn't be better. That's how arguments that are
implicitly pass-by-reference are passed. Also struct return values
are forced to lval in stack-allocated memory.
Furthermore, malloc would not be possible everywhere (e.g. on GPUs);
stack allocation would be supported by more platforms.
There is gdbarch_reserve_stack_space to allocate space on stack,
but it needs to be passed the current stack pointer. I don't know
how easy it is to get and set the SP in this context.
> + CORE_ADDR addr = value_as_address (addr_val);
> + write_memory (addr, new_value->contents ().data (), length);
> + new_value = value_at_lazy (new_value->type (), addr);
IMHO, we could use
CORE_ADDR addr = allocate_space_in_inferior (length); // Or stack space.
new_value->force_lval (addr);
for some simplification.
> + }
> +
> new_value = value_ref (new_value, type->code ());
> return new_value;
> }
> diff --git a/gdb/testsuite/gdb.cp/ref-params.cc
> b/gdb/testsuite/gdb.cp/ref-params.cc
> index 12e2716b435..3c1aa82396a 100644
> --- a/gdb/testsuite/gdb.cp/ref-params.cc
> +++ b/gdb/testsuite/gdb.cp/ref-params.cc
> @@ -60,6 +60,68 @@ int mf2(MultiChild& C)
> return mf1(C);
> }
>
> +/* A class to be used by functions and methods exercising c++/25957.
> */
> +class TestClass
> +{
> + public:
> + int value;
> +
> + TestClass (int v) : value (v) {}
> +
> + int
> + const_ref_method (const int &x) const
> + {
> + return value + x;
> + }
> +
> + int
> + const_ref_method (const TestClass &obj) const
> + {
> + return value + obj.value;
> + }
> +
> + int
> + ref_method (int &x)
> + {
> + return value + 2 * x;
> + }
> +
> + int
> + ref_method (TestClass &obj)
> + {
> + return value + 2 * obj.value;
> + }
> +};
> +
> +/* Define globals to be used by functions and methods exercising
> c++/25957. */
> +int global_int = 42;
> +TestClass global_obj (10);
> +
> +/* Helper functions to test reference parameter behavior for c++/25957.
> */
> +int
> +const_ref_func (const int &x)
> +{
> + return x * 2;
> +}
> +
> +int
> +const_ref_func (const TestClass &obj)
> +{
> + return obj.value * 2;
> +}
> +
> +int
> +ref_func (int &x)
> +{
> + return x + 1;
> +}
> +
> +int
> +ref_func (TestClass &obj)
> +{
> + return obj.value + 1;
> +}
> +
> int main(void)
> {
> Child Q(42);
> @@ -76,5 +138,36 @@ int main(void)
>
> mf2(MQ); /* Set breakpoint MQ here. */
>
> - return 0;
> + TestClass obj (5);
> + int local_var = 15;
> +
> + /* Prevent compiler from optimizing away the function and method
> calls. */
> + int dummy_int = 99;
> + (void) const_ref_func (dummy_int);
> + (void) const_ref_func (global_int);
> + (void) const_ref_func (obj);
> + (void) const_ref_func (global_obj);
> + (void) ref_func (dummy_int);
> + (void) ref_func (global_int);
> + (void) ref_func (obj);
> + (void) ref_func (global_obj);
> + (void) obj.const_ref_method (dummy_int);
> + (void) obj.const_ref_method (global_int);
> + (void) obj.const_ref_method (obj);
> + (void) obj.const_ref_method (global_obj);
> + (void) obj.ref_method (dummy_int);
> + (void) obj.ref_method (global_int);
> + (void) obj.ref_method (obj);
> + (void) obj.ref_method (global_obj);
> + (void) global_obj.const_ref_method (dummy_int);
> + (void) global_obj.const_ref_method (global_int);
> + (void) global_obj.const_ref_method (obj);
> + (void) global_obj.const_ref_method (global_obj);
> + (void) global_obj.ref_method (dummy_int);
> + (void) global_obj.ref_method (global_int);
> + (void) global_obj.ref_method (obj);
> + (void) global_obj.ref_method (global_obj);
> +
> + /* Breakpoint here for c++/25957 testing. */
> + return 0; /* breakpoint-here */
> }
> diff --git a/gdb/testsuite/gdb.cp/ref-params.exp
> b/gdb/testsuite/gdb.cp/ref-params.exp
> index b61055e9f50..a94927fae56 100644
> --- a/gdb/testsuite/gdb.cp/ref-params.exp
> +++ b/gdb/testsuite/gdb.cp/ref-params.exp
> @@ -63,3 +63,125 @@ gdb_test "print f1(MQR)" ".* = 53"
> gdb_test "print mf1(MQR)" ".* = 106"
> gdb_test "print mf2(MQR)" ".* = 106"
> gdb_test "print f3(Q.id)" ".* = 42"
> +
> +# Inferior function call tests which have reference arguments.
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
> +gdb_start_again "breakpoint-here"
> +
> +# Test functions taking const reference parameter.
> +gdb_test "print const_ref_func(10)" \
> + "= 20" \
> + "call function with const ref param and literal"
> +
> +gdb_test "print const_ref_func(global_int)" \
> + "= 84" \
> + "call function with const ref param and global variable"
> +
> +gdb_test "print const_ref_func(local_var)" \
> + "= 30" \
> + "call function with const ref param and local variable"
> +
> +gdb_test "print const_ref_func(obj)" \
> + "= 10" \
> + "call function with const ref param and object"
> +
> +gdb_test "print const_ref_func(global_obj)" \
> + "= 20" \
> + "call function with const ref param and global object"
Another potentially interesting testcase would be passing
a "literal" object, like this:
print const_ref_func((TestClass) {42})
This case is also fixed with your patch.
> +# Test functions taking non-const reference parameter.
> +gdb_test "print ref_func(10)" \
> + "Cannot resolve function ref_func to any overloaded instance" \
> + "call function with non-const ref param and literal"
> +
> +gdb_test "print ref_func(global_int)" \
> + " = 43" \
> + "call function with non-const ref param and global variable"
> +
> +gdb_test "print ref_func(local_var)" \
> + " = 16" \
> + "call function with non-const ref param and local variable"
> +
> +gdb_test "print ref_func(obj)" \
> + "= 6" \
> + "call function with non-const ref param and object"
> +
> +gdb_test "print ref_func(global_obj)" \
> + "= 11" \
> + "call function with non-const ref param and global object"
> +
> +# Test methods taking constant reference parameter.
> +gdb_test "print obj.const_ref_method(5)" \
> + "= 10" \
> + "call const method with const ref param and literal"
> +
> +gdb_test "print obj.const_ref_method(global_int)" \
> + "= 47" \
> + "call const method with const ref param and global variable"
> +
> +gdb_test "print obj.const_ref_method(local_var)" \
> + "= 20" \
> + "call const method with const ref param and local variable"
> +
> +gdb_test "print obj.const_ref_method (obj)" \
Nit: The other tests don't have space before parenthesis.
> + "= 10" \
> + "call method with const ref param and object"
> +
> +# Test methods taking non-const reference parameters.
> +gdb_test "print obj.ref_method(5)" \
> + "Cannot resolve method TestClass::ref_method to any overloaded
> instance" \
> + "call method with non-const ref param and literal"
> +
> +gdb_test "print obj.ref_method(global_int)" \
> + "= 89" \
> + "cal method with non-const ref param and global variable"
> +
> +gdb_test "print obj.ref_method(local_var)" \
> + " = 35" \
> + "call method with non-const ref param and local variable"
> +
> +gdb_test "print obj.ref_method(obj)" \
> + "= 15" \
> + "call method with non-const ref param and object"
> +
> +# Test global_obj methods taking constant reference parameter.
> +gdb_test "print global_obj.const_ref_method(5)" \
> + "= 15" \
> + "call global const method with const ref param and literal"
> +
> +gdb_test "print global_obj.const_ref_method(global_int)" \
> + "= 52" \
> + "call global const method with const ref param and global variable"
> +
> +gdb_test "print global_obj.const_ref_method(local_var)" \
> + "= 25" \
> + "call global const method with const ref param and local variable"
> +
> +gdb_test "print global_obj.const_ref_method(obj)" \
> + "= 15" \
> + "call global method with const ref param and object"
> +
> +gdb_test "print global_obj.const_ref_method(global_obj)" \
> + "= 20" \
> + "call global method with const ref param and global object"
> +
> +# Test global_obj methods taking non-const reference parameters.
> +gdb_test "print global_obj.ref_method(5)" \
> + "Cannot resolve method TestClass::ref_method to any overloaded
> instance" \
> + "call global method with non-const ref param and literal"
> +
> +gdb_test "print global_obj.ref_method(global_int)" \
> + "= 94" \
> + "call global method with non-const ref param and global variable"
> +
> +gdb_test "print global_obj.ref_method(local_var)" \
> + "= 40" \
> + "call global method with non-const ref param and local variable"
> +
> +gdb_test "print global_obj.ref_method(obj)" \
> + "= 20" \
> + "call global method with non-const ref param and object"
> +
> +gdb_test "print global_obj.ref_method(global_obj)" \
> + "= 30" \
> + "call global method with non-const ref param and global object"
> \ No newline at end of file
Could you please add a new line at the end?
Regards,
-Baris
> diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> index bd6933673db..b9da32c244e 100644
> --- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> +++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> @@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
>
> gdb_test "print f (ci)" "2" "lvalue reference to const overload"
>
> -setup_kfail "c++/15372" "*-*-*"
> gdb_test "print f (3)" "3" "rvalue reference overload"
>
> gdb_test "print g (i)" \
>
> base-commit: 01be62d46b2e05e5a994b080974dd3832755e137
> --
> 2.52.0
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] infcall: Add support for integer literals as reference function paramters
2026-01-23 14:07 ` Aktemur, Tankut Baris
@ 2026-01-27 18:43 ` Keith Seitz
0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2026-01-27 18:43 UTC (permalink / raw)
To: Aktemur, Tankut Baris, gdb-patches
Hi!
On 1/23/26 6:07 AM, Aktemur, Tankut Baris wrote:
> On Thursday, January 22, 2026 8:06 PM, Keith Seitz wrote:
>> diff --git a/gdb/infcall.c b/gdb/infcall.c
>> index dcbae679d07..b836a868d15 100644
>> --- a/gdb/infcall.c
>> +++ b/gdb/infcall.c
>> @@ -276,10 +276,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct
>> value *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
>> - if the value was not previously in memory - in some cases
>> - we should clearly be allowing this, but how? */
>> + convert it back to a reference. For C++ reference parameters,
>> + if the value is not already in memory (e.g., a literal), we
>> + need to allocate space in the inferior and copy the value there.
>> + If the value is already in memory, we can use its address
>> + directly. */
>> new_value = value_cast (type->target_type (), arg);
>> + if (new_value->lval () != lval_memory
>> + && language_pass_by_reference (new_value->type ())
>> + .trivially_copyable)
>> + {
>> + LONGEST length = check_typedef (new_value->type ())->length ();
>> + struct value *addr_val = value_allocate_space_in_inferior
>> (length);
>
> This uses malloc to allocate the space. I was wondering if allocating
> space on the stack wouldn't be better. That's how arguments that are
> implicitly pass-by-reference are passed. Also struct return values
> are forced to lval in stack-allocated memory.
>
> Furthermore, malloc would not be possible everywhere (e.g. on GPUs);
> stack allocation would be supported by more platforms.
>
> There is gdbarch_reserve_stack_space to allocate space on stack,
> but it needs to be passed the current stack pointer. I don't know
> how easy it is to get and set the SP in this context.
Yes, I think we can use stack for this -- a lot of
call_function_by_hand_dummy does this already. I've made this change.
>> + CORE_ADDR addr = value_as_address (addr_val);
>> + write_memory (addr, new_value->contents ().data (), length);
>> + new_value = value_at_lazy (new_value->type (), addr);
>
> IMHO, we could use
>
> CORE_ADDR addr = allocate_space_in_inferior (length); // Or stack space.
> new_value->force_lval (addr);
I've made this change.
>> diff --git a/gdb/testsuite/gdb.cp/ref-params.exp
>> b/gdb/testsuite/gdb.cp/ref-params.exp
>> index b61055e9f50..a94927fae56 100644
>> --- a/gdb/testsuite/gdb.cp/ref-params.exp
>> +++ b/gdb/testsuite/gdb.cp/ref-params.exp
[snip]
>> +gdb_test "print const_ref_func(global_obj)" \
>> + "= 20" \
>> + "call function with const ref param and global object"
>
> Another potentially interesting testcase would be passing
> a "literal" object, like this:
>
> print const_ref_func((TestClass) {42})
>
> This case is also fixed with your patch.
I've added these tests.
>
>> +# Test functions taking non-const reference parameter.
>> +gdb_test "print ref_func(10)" \
>> + "Cannot resolve function ref_func to any overloaded instance" \
>> + "call function with non-const ref param and literal"
>> +
>> +gdb_test "print ref_func(global_int)" \
>> + " = 43" \
>> + "call function with non-const ref param and global variable"
>> +
>> +gdb_test "print ref_func(local_var)" \
>> + " = 16" \
>> + "call function with non-const ref param and local variable"
>> +
>> +gdb_test "print ref_func(obj)" \
>> + "= 6" \
>> + "call function with non-const ref param and object"
>> +
>> +gdb_test "print ref_func(global_obj)" \
>> + "= 11" \
>> + "call function with non-const ref param and global object"
>> +
>> +# Test methods taking constant reference parameter.
>> +gdb_test "print obj.const_ref_method(5)" \
>> + "= 10" \
>> + "call const method with const ref param and literal"
>> +
>> +gdb_test "print obj.const_ref_method(global_int)" \
>> + "= 47" \
>> + "call const method with const ref param and global variable"
>> +
>> +gdb_test "print obj.const_ref_method(local_var)" \
>> + "= 20" \
>> + "call const method with const ref param and local variable"
>> +
>> +gdb_test "print obj.const_ref_method (obj)" \
>
> Nit: The other tests don't have space before parenthesis.
>
You are correct, and trailing parentheses are not permitted in test
names like this (or used to anyway). I've corrected this typo.
Good eye!
[snip]
>> +gdb_test "print global_obj.ref_method(global_obj)" \
>> + "= 30" \
>> + "call global method with non-const ref param and global object"
>> \ No newline at end of file
>
> Could you please add a new line at the end?
Done.
I will send v4 [note I have an off-by-one error in my versioning].
Thank you for your review!
Keith
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v4] infcall: Add support for integer literals as reference function paramters
2025-10-16 15:48 [PATCH] infcall: Add support for integer literals as reference function paramters Keith Seitz
2025-10-17 14:49 ` Tom Tromey
2025-10-20 19:36 ` [PATCH v2] " Keith Seitz
@ 2026-01-27 19:01 ` Keith Seitz
2026-01-28 8:24 ` Aktemur, Tankut Baris
` (2 more replies)
2026-03-12 14:14 ` [PATCH v5] infcall: Add support for integer literals as reference function parameters Keith Seitz
2026-03-12 17:12 ` [PATCH v6] " Keith Seitz
4 siblings, 3 replies; 25+ messages in thread
From: Keith Seitz @ 2026-01-27 19:01 UTC (permalink / raw)
To: gdb-patches
This patch attempts to mitigate the shortcomings of passing literals
to inferior function calls requiring references. The specific use case here
is std::map's operator[]:
std::map int_map<int, int>;
int_map[1] = 10;
(gdb) print int_map[1]
Attempt to take address of value not located in memory.
This is occurring because while value_coerce_to_target understands
that some values need to be allocated and copied to the inferior's
memory, it only considers the actual parsed type of the argument value,
ignoring the actual type of the function parameter. That is,
in this specific case, the value's parsed type is TYPE_CODE_INT, but
the function requires TYPE_CODE_REF. We need to account for the
reference.
In value_arg_coerce, we have special handling for references, but it
has not specifically dealt with this case. It now checks if the
reference is in memory, and if it isn't, it copies it, if the type
is trivially copyable.
As a result of this patch, the last remaining failure in c++/15372 is now
fixed, and that bug can be closed.
With this patch, we can now print map entries with integer keys:
(gdb) print int_map[1]
$1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
Changes in v4
- Allocate to stack instead of heap
- Use value::force_lval to simply copying to inferior memory
- Add some addition tests
Changes in v3
- Move logic to value_arg_coerce
- Add some attempt to limit copying to trivially copyable types
---
gdb/infcall.c | 26 +++-
gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
4 files changed, 261 insertions(+), 7 deletions(-)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index dcbae679d07..c4e9605a665 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -63,6 +63,8 @@ static bool debug_infcall = false;
#define INFCALL_SCOPED_DEBUG_START_END(fmt, ...) \
scoped_debug_start_end (debug_infrun, "infcall", fmt, ##__VA_ARGS__)
+static CORE_ADDR reserve_stack_space (const type *values_type, CORE_ADDR &sp);
+
/* Implement 'show debug infcall'. */
static void
@@ -246,7 +248,8 @@ show_unwind_on_timeout_p (struct ui_file *file, int from_tty,
static struct value *
value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
- struct type *param_type, int is_prototyped)
+ struct type *param_type, int is_prototyped,
+ CORE_ADDR *sp, struct thread_info *call_thread)
{
const struct builtin_type *builtin = builtin_type (gdbarch);
struct type *arg_type = check_typedef (arg->type ());
@@ -276,10 +279,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
- if the value was not previously in memory - in some cases
- we should clearly be allowing this, but how? */
+ convert it back to a reference. If the value is not already
+ in memory (e.g., a literal), we need to allocate space in the
+ inferior and copy it there. */
new_value = value_cast (type->target_type (), arg);
+ if (new_value->lval () != lval_memory
+ && language_pass_by_reference (new_value->type ())
+ .trivially_copyable)
+ {
+ CORE_ADDR addr;
+
+ gdb_assert (sp != nullptr);
+ gdb_assert (call_thread != nullptr);
+ addr = reserve_stack_space (new_value->type (), *sp);
+ new_value->force_lval (addr);
+ push_thread_stack_temporary (call_thread, new_value);
+ }
+
new_value = value_ref (new_value, type->code ());
return new_value;
}
@@ -1335,7 +1351,7 @@ call_function_by_hand_dummy (struct value *function,
value *original_arg = args[i];
args[i] = value_arg_coerce (gdbarch, args[i],
- param_type, prototyped);
+ param_type, prototyped, &sp, call_thread.get ());
if (param_type == NULL)
continue;
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
index 12e2716b435..3c1aa82396a 100644
--- a/gdb/testsuite/gdb.cp/ref-params.cc
+++ b/gdb/testsuite/gdb.cp/ref-params.cc
@@ -60,6 +60,68 @@ int mf2(MultiChild& C)
return mf1(C);
}
+/* A class to be used by functions and methods exercising c++/25957. */
+class TestClass
+{
+ public:
+ int value;
+
+ TestClass (int v) : value (v) {}
+
+ int
+ const_ref_method (const int &x) const
+ {
+ return value + x;
+ }
+
+ int
+ const_ref_method (const TestClass &obj) const
+ {
+ return value + obj.value;
+ }
+
+ int
+ ref_method (int &x)
+ {
+ return value + 2 * x;
+ }
+
+ int
+ ref_method (TestClass &obj)
+ {
+ return value + 2 * obj.value;
+ }
+};
+
+/* Define globals to be used by functions and methods exercising c++/25957. */
+int global_int = 42;
+TestClass global_obj (10);
+
+/* Helper functions to test reference parameter behavior for c++/25957. */
+int
+const_ref_func (const int &x)
+{
+ return x * 2;
+}
+
+int
+const_ref_func (const TestClass &obj)
+{
+ return obj.value * 2;
+}
+
+int
+ref_func (int &x)
+{
+ return x + 1;
+}
+
+int
+ref_func (TestClass &obj)
+{
+ return obj.value + 1;
+}
+
int main(void)
{
Child Q(42);
@@ -76,5 +138,36 @@ int main(void)
mf2(MQ); /* Set breakpoint MQ here. */
- return 0;
+ TestClass obj (5);
+ int local_var = 15;
+
+ /* Prevent compiler from optimizing away the function and method calls. */
+ int dummy_int = 99;
+ (void) const_ref_func (dummy_int);
+ (void) const_ref_func (global_int);
+ (void) const_ref_func (obj);
+ (void) const_ref_func (global_obj);
+ (void) ref_func (dummy_int);
+ (void) ref_func (global_int);
+ (void) ref_func (obj);
+ (void) ref_func (global_obj);
+ (void) obj.const_ref_method (dummy_int);
+ (void) obj.const_ref_method (global_int);
+ (void) obj.const_ref_method (obj);
+ (void) obj.const_ref_method (global_obj);
+ (void) obj.ref_method (dummy_int);
+ (void) obj.ref_method (global_int);
+ (void) obj.ref_method (obj);
+ (void) obj.ref_method (global_obj);
+ (void) global_obj.const_ref_method (dummy_int);
+ (void) global_obj.const_ref_method (global_int);
+ (void) global_obj.const_ref_method (obj);
+ (void) global_obj.const_ref_method (global_obj);
+ (void) global_obj.ref_method (dummy_int);
+ (void) global_obj.ref_method (global_int);
+ (void) global_obj.ref_method (obj);
+ (void) global_obj.ref_method (global_obj);
+
+ /* Breakpoint here for c++/25957 testing. */
+ return 0; /* breakpoint-here */
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
index b61055e9f50..31144fcba21 100644
--- a/gdb/testsuite/gdb.cp/ref-params.exp
+++ b/gdb/testsuite/gdb.cp/ref-params.exp
@@ -63,3 +63,149 @@ gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"
+
+# Inferior function call tests which have reference arguments.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
+gdb_start_again "breakpoint-here"
+
+# Test functions taking const reference parameter.
+gdb_test "print const_ref_func(10)" \
+ "= 20" \
+ "call function with const ref param and literal"
+
+gdb_test "print const_ref_func(global_int)" \
+ "= 84" \
+ "call function with const ref param and global variable"
+
+gdb_test "print const_ref_func(local_var)" \
+ "= 30" \
+ "call function with const ref param and local variable"
+
+gdb_test "print const_ref_func(obj)" \
+ "= 10" \
+ "call function with const ref param and object"
+
+gdb_test "print const_ref_func(global_obj)" \
+ "= 20" \
+ "call function with const ref param and global object"
+
+gdb_test "print const_ref_func((TestClass) {42})" \
+ "= 84" \
+ "call function with const ref param and literal object"
+
+# Test functions taking non-const reference parameter.
+gdb_test "print ref_func(10)" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with non-const ref param and literal"
+
+gdb_test "print ref_func(global_int)" \
+ " = 43" \
+ "call function with non-const ref param and global variable"
+
+gdb_test "print ref_func(local_var)" \
+ " = 16" \
+ "call function with non-const ref param and local variable"
+
+gdb_test "print ref_func(obj)" \
+ "= 6" \
+ "call function with non-const ref param and object"
+
+gdb_test "print ref_func(global_obj)" \
+ "= 11" \
+ "call function with non-const ref param and global object"
+
+gdb_test "print ref_func((TestClass) {42})" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with ref param and literal object"
+
+# Test methods taking constant reference parameter.
+gdb_test "print obj.const_ref_method(5)" \
+ "= 10" \
+ "call const method with const ref param and literal"
+
+gdb_test "print obj.const_ref_method(global_int)" \
+ "= 47" \
+ "call const method with const ref param and global variable"
+
+gdb_test "print obj.const_ref_method(local_var)" \
+ "= 20" \
+ "call const method with const ref param and local variable"
+
+gdb_test "print obj.const_ref_method(obj)" \
+ "= 10" \
+ "call method with const ref param and object"
+
+gdb_test "print obj.const_ref_method((TestClass) {42})" \
+ "= 47" \
+ "call method with const ref param and literal object"
+
+# Test methods taking non-const reference parameters.
+gdb_test "print obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal"
+
+gdb_test "print obj.ref_method(global_int)" \
+ "= 89" \
+ "cal method with non-const ref param and global variable"
+
+gdb_test "print obj.ref_method(local_var)" \
+ " = 35" \
+ "call method with non-const ref param and local variable"
+
+gdb_test "print obj.ref_method(obj)" \
+ "= 15" \
+ "call method with non-const ref param and object"
+
+gdb_test "print obj.ref_method((TestClass) {42})" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal object"
+
+# Test global_obj methods taking constant reference parameter.
+gdb_test "print global_obj.const_ref_method(5)" \
+ "= 15" \
+ "call global const method with const ref param and literal"
+
+gdb_test "print global_obj.const_ref_method(global_int)" \
+ "= 52" \
+ "call global const method with const ref param and global variable"
+
+gdb_test "print global_obj.const_ref_method(local_var)" \
+ "= 25" \
+ "call global const method with const ref param and local variable"
+
+gdb_test "print global_obj.const_ref_method(obj)" \
+ "= 15" \
+ "call global method with const ref param and object"
+
+gdb_test "print global_obj.const_ref_method(global_obj)" \
+ "= 20" \
+ "call global method with const ref param and global object"
+
+gdb_test "print global_obj.const_ref_method((TestClass) {42})" \
+ "= 52" \
+ "call global method with const ref param and literal object"
+
+# Test global_obj methods taking non-const reference parameters.
+gdb_test "print global_obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal"
+
+gdb_test "print global_obj.ref_method(global_int)" \
+ "= 94" \
+ "call global method with non-const ref param and global variable"
+
+gdb_test "print global_obj.ref_method(local_var)" \
+ "= 40" \
+ "call global method with non-const ref param and local variable"
+
+gdb_test "print global_obj.ref_method(obj)" \
+ "= 20" \
+ "call global method with non-const ref param and object"
+
+gdb_test "print global_obj.ref_method(global_obj)" \
+ "= 30" \
+ "call global method with non-const ref param and global object"
+
+gdb_test "print global_obj.ref_method ((TestClass) {42})" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal object"
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index bd6933673db..b9da32c244e 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
gdb_test "print f (ci)" "2" "lvalue reference to const overload"
-setup_kfail "c++/15372" "*-*-*"
gdb_test "print f (3)" "3" "rvalue reference overload"
gdb_test "print g (i)" \
base-commit: 01be62d46b2e05e5a994b080974dd3832755e137
--
2.52.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* RE: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-01-27 19:01 ` [PATCH v4] " Keith Seitz
@ 2026-01-28 8:24 ` Aktemur, Tankut Baris
2026-01-28 13:54 ` Andrew Burgess
2026-01-30 20:59 ` Tom Tromey
2 siblings, 0 replies; 25+ messages in thread
From: Aktemur, Tankut Baris @ 2026-01-28 8:24 UTC (permalink / raw)
To: Keith Seitz, gdb-patches
Hello Keith,
The commit title has a typo: "paramters".
On Tuesday, January 27, 2026 8:02 PM, Keith Seitz wrote:
> This patch attempts to mitigate the shortcomings of passing literals
> to inferior function calls requiring references. The specific use case
> here
> is std::map's operator[]:
>
> std::map int_map<int, int>;
> int_map[1] = 10;
> (gdb) print int_map[1]
> Attempt to take address of value not located in memory.
>
> This is occurring because while value_coerce_to_target understands
> that some values need to be allocated and copied to the inferior's
> memory, it only considers the actual parsed type of the argument value,
> ignoring the actual type of the function parameter. That is,
> in this specific case, the value's parsed type is TYPE_CODE_INT, but
> the function requires TYPE_CODE_REF. We need to account for the
> reference.
>
> In value_arg_coerce, we have special handling for references, but it
> has not specifically dealt with this case. It now checks if the
> reference is in memory, and if it isn't, it copies it, if the type
> is trivially copyable.
>
> As a result of this patch, the last remaining failure in c++/15372 is
> now
> fixed, and that bug can be closed.
>
> With this patch, we can now print map entries with integer keys:
>
> (gdb) print int_map[1]
> $1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int
> const, int> > >::mapped_type &) @0x41f2d4: 10
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
>
> Changes in v4
> - Allocate to stack instead of heap
> - Use value::force_lval to simply copying to inferior memory
> - Add some addition tests
>
> Changes in v3
> - Move logic to value_arg_coerce
> - Add some attempt to limit copying to trivially copyable types
> ---
> gdb/infcall.c | 26 +++-
> gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
> gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
> gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
> 4 files changed, 261 insertions(+), 7 deletions(-)
>
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index dcbae679d07..c4e9605a665 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -63,6 +63,8 @@ static bool debug_infcall = false;
> #define INFCALL_SCOPED_DEBUG_START_END(fmt, ...) \
> scoped_debug_start_end (debug_infrun, "infcall", fmt, ##__VA_ARGS__)
>
> +static CORE_ADDR reserve_stack_space (const type *values_type,
> CORE_ADDR &sp);
> +
> /* Implement 'show debug infcall'. */
>
> static void
> @@ -246,7 +248,8 @@ show_unwind_on_timeout_p (struct ui_file *file, int
> from_tty,
>
> static struct value *
> value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
> - struct type *param_type, int is_prototyped)
> + struct type *param_type, int is_prototyped,
> + CORE_ADDR *sp, struct thread_info *call_thread)
"struct" keywords can be removed.
> {
> const struct builtin_type *builtin = builtin_type (gdbarch);
> struct type *arg_type = check_typedef (arg->type ());
> @@ -276,10 +279,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct
> value *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
> - if the value was not previously in memory - in some cases
> - we should clearly be allowing this, but how? */
> + convert it back to a reference. If the value is not already
> + in memory (e.g., a literal), we need to allocate space in the
> + inferior and copy it there. */
> new_value = value_cast (type->target_type (), arg);
> + if (new_value->lval () != lval_memory
> + && language_pass_by_reference (new_value->type ())
> + .trivially_copyable)
> + {
> + CORE_ADDR addr;
This declaration can be moved to its definition below.
I also ran the testsuite with the default board file and
did not see any regression.
Reviewed-By: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Regards,
-Baris
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-01-27 19:01 ` [PATCH v4] " Keith Seitz
2026-01-28 8:24 ` Aktemur, Tankut Baris
@ 2026-01-28 13:54 ` Andrew Burgess
2026-02-02 17:05 ` Aktemur, Tankut Baris
2026-02-02 17:21 ` Keith Seitz
2026-01-30 20:59 ` Tom Tromey
2 siblings, 2 replies; 25+ messages in thread
From: Andrew Burgess @ 2026-01-28 13:54 UTC (permalink / raw)
To: Keith Seitz, gdb-patches
Keith Seitz <keiths@redhat.com> writes:
> This patch attempts to mitigate the shortcomings of passing literals
> to inferior function calls requiring references. The specific use case here
> is std::map's operator[]:
>
> std::map int_map<int, int>;
> int_map[1] = 10;
> (gdb) print int_map[1]
> Attempt to take address of value not located in memory.
>
> This is occurring because while value_coerce_to_target understands
> that some values need to be allocated and copied to the inferior's
> memory, it only considers the actual parsed type of the argument value,
> ignoring the actual type of the function parameter. That is,
> in this specific case, the value's parsed type is TYPE_CODE_INT, but
> the function requires TYPE_CODE_REF. We need to account for the
> reference.
>
> In value_arg_coerce, we have special handling for references, but it
> has not specifically dealt with this case. It now checks if the
> reference is in memory, and if it isn't, it copies it, if the type
> is trivially copyable.
>
> As a result of this patch, the last remaining failure in c++/15372 is now
> fixed, and that bug can be closed.
>
> With this patch, we can now print map entries with integer keys:
>
> (gdb) print int_map[1]
> $1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
>
> Changes in v4
> - Allocate to stack instead of heap
I'm interested by this change. Within value_arg_coerce, a few lines
before your change, there's this comment:
/* Force the value to the target if we will need its address. At
this point, we could allocate arguments on the stack instead of
calling malloc if we knew that their addresses would not be
saved by the called function. */
arg = value_coerce_to_target (arg);
I don't believe there's anything stopping the inferior function taking
the address of the reference argument and storing it. Could you explain
this change a little more?
> - Use value::force_lval to simply copying to inferior memory
> - Add some addition tests
>
> Changes in v3
> - Move logic to value_arg_coerce
> - Add some attempt to limit copying to trivially copyable types
> ---
> gdb/infcall.c | 26 +++-
> gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
> gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
> gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
> 4 files changed, 261 insertions(+), 7 deletions(-)
>
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index dcbae679d07..c4e9605a665 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -63,6 +63,8 @@ static bool debug_infcall = false;
> #define INFCALL_SCOPED_DEBUG_START_END(fmt, ...) \
> scoped_debug_start_end (debug_infrun, "infcall", fmt, ##__VA_ARGS__)
>
> +static CORE_ADDR reserve_stack_space (const type *values_type, CORE_ADDR &sp);
> +
> /* Implement 'show debug infcall'. */
>
> static void
> @@ -246,7 +248,8 @@ show_unwind_on_timeout_p (struct ui_file *file, int from_tty,
>
> static struct value *
> value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
> - struct type *param_type, int is_prototyped)
> + struct type *param_type, int is_prototyped,
> + CORE_ADDR *sp, struct thread_info *call_thread)
> {
> const struct builtin_type *builtin = builtin_type (gdbarch);
> struct type *arg_type = check_typedef (arg->type ());
> @@ -276,10 +279,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
> - if the value was not previously in memory - in some cases
> - we should clearly be allowing this, but how? */
> + convert it back to a reference. If the value is not already
> + in memory (e.g., a literal), we need to allocate space in the
> + inferior and copy it there. */
> new_value = value_cast (type->target_type (), arg);
> + if (new_value->lval () != lval_memory
> + && language_pass_by_reference (new_value->type ())
> + .trivially_copyable)
> + {
> + CORE_ADDR addr;
> +
> + gdb_assert (sp != nullptr);
Given reserve_stack_space expects a reference to a CORE_ADDR, I think
I'd just make the argument to this function 'CORE_ADDR &sp', then this
assert can be dropped.
Thanks,
Andrew
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-01-27 19:01 ` [PATCH v4] " Keith Seitz
2026-01-28 8:24 ` Aktemur, Tankut Baris
2026-01-28 13:54 ` Andrew Burgess
@ 2026-01-30 20:59 ` Tom Tromey
2026-02-02 16:58 ` Keith Seitz
2 siblings, 1 reply; 25+ messages in thread
From: Tom Tromey @ 2026-01-30 20:59 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> - Allocate to stack instead of heap
I'm curious why this change was made.
Often I think gdb just coerces to memory via malloc.
Also other calls in this area seem to check
thread_stack_temporaries_enabled_p. Not sure if that's needed?
Maybe it's expected to be set and this can just be asserted?
This is not really an area I know much about.
Keith> + if (new_value->lval () != lval_memory
Keith> + && language_pass_by_reference (new_value->type ())
Keith> + .trivially_copyable)
This subexpression should be parenthesized and the '.' lined up with the
'l'.
Tom
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-01-30 20:59 ` Tom Tromey
@ 2026-02-02 16:58 ` Keith Seitz
2026-02-02 17:22 ` Aktemur, Tankut Baris
2026-02-12 16:31 ` Tom Tromey
0 siblings, 2 replies; 25+ messages in thread
From: Keith Seitz @ 2026-02-02 16:58 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 1/30/26 12:59 PM, Tom Tromey wrote:
>>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
>
> Keith> - Allocate to stack instead of heap
>
> I'm curious why this change was made.
> Often I think gdb just coerces to memory via malloc.
I was persuaded by another reviewer's comments[1]:
> This uses malloc to allocate the space. I was wondering if allocating
> space on the stack wouldn't be better. That's how arguments that are
> implicitly pass-by-reference are passed. Also struct return values
> are forced to lval in stack-allocated memory.
>
> Furthermore, malloc would not be possible everywhere (e.g. on GPUs);
> stack allocation would be supported by more platforms.
I was unable to conceive of a counterpoint to this last argument,
hence the change.
> Also other calls in this area seem to check
> thread_stack_temporaries_enabled_p. Not sure if that's needed?
> Maybe it's expected to be set and this can just be asserted?
>
> This is not really an area I know much about.
That makes two of us. I will look into the use of
thread_stack_temporaries_enabled_p.
> Keith> + if (new_value->lval () != lval_memory
> Keith> + && language_pass_by_reference (new_value->type ())
> Keith> + .trivially_copyable)
>
> This subexpression should be parenthesized and the '.' lined up with the
> 'l'.
Will do.
Thank you for taking a look,
Keith
[1]
https://inbox.sourceware.org/gdb-patches/92575c2eb6805095b41ebbe62ba99b81e4e5dd63.1760629738.git.keiths@redhat.com/T/#mc60c810be7d4054faa7699a453c00cdf6b21fc15
^ permalink raw reply [flat|nested] 25+ messages in thread
* RE: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-01-28 13:54 ` Andrew Burgess
@ 2026-02-02 17:05 ` Aktemur, Tankut Baris
2026-02-02 17:21 ` Keith Seitz
1 sibling, 0 replies; 25+ messages in thread
From: Aktemur, Tankut Baris @ 2026-02-02 17:05 UTC (permalink / raw)
To: Andrew Burgess, Keith Seitz, gdb-patches, Tom Tromey
On Wednesday, January 28, 2026 2:55 PM, Andrew Burgess wrote:
> Keith Seitz <keiths@redhat.com> writes:
>
> > This patch attempts to mitigate the shortcomings of passing literals
> > to inferior function calls requiring references. The specific use
> case here
> > is std::map's operator[]:
> >
> > std::map int_map<int, int>;
> > int_map[1] = 10;
> > (gdb) print int_map[1]
> > Attempt to take address of value not located in memory.
> >
> > This is occurring because while value_coerce_to_target understands
> > that some values need to be allocated and copied to the inferior's
> > memory, it only considers the actual parsed type of the argument
> value,
> > ignoring the actual type of the function parameter. That is,
> > in this specific case, the value's parsed type is TYPE_CODE_INT, but
> > the function requires TYPE_CODE_REF. We need to account for the
> > reference.
> >
> > In value_arg_coerce, we have special handling for references, but it
> > has not specifically dealt with this case. It now checks if the
> > reference is in memory, and if it isn't, it copies it, if the type
> > is trivially copyable.
> >
> > As a result of this patch, the last remaining failure in c++/15372 is
> now
> > fixed, and that bug can be closed.
> >
> > With this patch, we can now print map entries with integer keys:
> >
> > (gdb) print int_map[1]
> > $1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int
> const, int> > >::mapped_type &) @0x41f2d4: 10
> >
> > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
> > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
> >
> > Changes in v4
> > - Allocate to stack instead of heap
>
> I'm interested by this change. Within value_arg_coerce, a few lines
> before your change, there's this comment:
>
> /* Force the value to the target if we will need its address. At
> this point, we could allocate arguments on the stack instead of
> calling malloc if we knew that their addresses would not be
> saved by the called function. */
> arg = value_coerce_to_target (arg);
>
> I don't believe there's anything stopping the inferior function taking
> the address of the reference argument and storing it. Could you explain
> this change a little more?
My review comment must have caused this change in v4. I'm sorry about that.
GDB allocates implicit pass-by-reference arguments on stack. It also allocates
struct return values on stack [1]. That is the reason why I had commented so.
Suppose I have a struct S and in the code there is
S *gp;
void func (S &s1) { gp = &s1; }
S bar () { return {99}; }
Then, in GDB if I do
(gdb) print func(bar())
the global pointer `gp` would be pointing to a stack-allocated object,
which is now garbage. I believe we should fix this then, right?
(It's a side topic and not directly part of Keith's patch.)
Regards,
-Baris
[1] infcall.c:
/* Reserve space for the return structure to be written on the
stack, if necessary.
While evaluating expressions, we reserve space on the stack for
return values of class type even if the language ABI and the target
ABI do not require that the return value be passed as a hidden first
argument. This is because we want to store the return value as an
on-stack temporary while the expression is being evaluated. This
enables us to have chained function calls in expressions.
Keeping the return values as on-stack temporaries while the expression
is being evaluated is OK because the thread is stopped until the
expression is completely evaluated. */
if (return_method != return_method_normal
|| (stack_temporaries && class_or_union_p (values_type)))
struct_addr = reserve_stack_space (values_type, sp);
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-01-28 13:54 ` Andrew Burgess
2026-02-02 17:05 ` Aktemur, Tankut Baris
@ 2026-02-02 17:21 ` Keith Seitz
1 sibling, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2026-02-02 17:21 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches
Hi,
Thank you for looking at my patch.
On 1/28/26 5:54 AM, Andrew Burgess wrote:
> Keith Seitz <keiths@redhat.com> writes:
>
>> Changes in v4
>> - Allocate to stack instead of heap
>
> I'm interested by this change. Within value_arg_coerce, a few lines
> before your change, there's this comment:
>
> /* Force the value to the target if we will need its address. At
> this point, we could allocate arguments on the stack instead of
> calling malloc if we knew that their addresses would not be
> saved by the called function. */
> arg = value_coerce_to_target (arg);
>
> I don't believe there's anything stopping the inferior function taking
> the address of the reference argument and storing it. Could you explain
> this change a little more?
Hmm... I see where you're headed with this, and I had not thought
of this possibility. This would certainly provide a counter-
argument to a previous review suggesting stack allocation.
However, if we malloc memory to hold this integer during the
function call, is this also not free'd after the call returns?
That pretty much leaves us in the same dilemma.
[Pardon my ignorance; I am just learning this code for the (nearly)
first time.]
>> - Use value::force_lval to simply copying to inferior memory
>> - Add some addition tests
>>
>> Changes in v3
>> - Move logic to value_arg_coerce
>> - Add some attempt to limit copying to trivially copyable types
>> ---
>> gdb/infcall.c | 26 +++-
>> gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
>> gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
>> gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
>> 4 files changed, 261 insertions(+), 7 deletions(-)
>>
>> diff --git a/gdb/infcall.c b/gdb/infcall.c
>> index dcbae679d07..c4e9605a665 100644
>> --- a/gdb/infcall.c
>> +++ b/gdb/infcall.c
>> @@ -63,6 +63,8 @@ static bool debug_infcall = false;
>> #define INFCALL_SCOPED_DEBUG_START_END(fmt, ...) \
>> scoped_debug_start_end (debug_infrun, "infcall", fmt, ##__VA_ARGS__)
>>
>> +static CORE_ADDR reserve_stack_space (const type *values_type, CORE_ADDR &sp);
>> +
>> /* Implement 'show debug infcall'. */
>>
>> static void
>> @@ -246,7 +248,8 @@ show_unwind_on_timeout_p (struct ui_file *file, int from_tty,
>>
>> static struct value *
>> value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
>> - struct type *param_type, int is_prototyped)
>> + struct type *param_type, int is_prototyped,
>> + CORE_ADDR *sp, struct thread_info *call_thread)
>> {
>> const struct builtin_type *builtin = builtin_type (gdbarch);
>> struct type *arg_type = check_typedef (arg->type ());
>> @@ -276,10 +279,23 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
>> - if the value was not previously in memory - in some cases
>> - we should clearly be allowing this, but how? */
>> + convert it back to a reference. If the value is not already
>> + in memory (e.g., a literal), we need to allocate space in the
>> + inferior and copy it there. */
>> new_value = value_cast (type->target_type (), arg);
>> + if (new_value->lval () != lval_memory
>> + && language_pass_by_reference (new_value->type ())
>> + .trivially_copyable)
>> + {
>> + CORE_ADDR addr;
>> +
>> + gdb_assert (sp != nullptr);
>
> Given reserve_stack_space expects a reference to a CORE_ADDR, I think
> I'd just make the argument to this function 'CORE_ADDR &sp', then this
> assert can be dropped.
I will make that change.
Thank you again for taking a look at this,
Keith
^ permalink raw reply [flat|nested] 25+ messages in thread
* RE: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-02-02 16:58 ` Keith Seitz
@ 2026-02-02 17:22 ` Aktemur, Tankut Baris
2026-02-12 16:31 ` Tom Tromey
1 sibling, 0 replies; 25+ messages in thread
From: Aktemur, Tankut Baris @ 2026-02-02 17:22 UTC (permalink / raw)
To: Keith Seitz, Tom Tromey; +Cc: gdb-patches
On Monday, February 2, 2026 5:58 PM, Keith Seitz wrote:
> On 1/30/26 12:59 PM, Tom Tromey wrote:
> >>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
> >
> > Keith> - Allocate to stack instead of heap
> >
> > I'm curious why this change was made.
> > Often I think gdb just coerces to memory via malloc.
>
> I was persuaded by another reviewer's comments[1]:
I'm sorry :/
> > This uses malloc to allocate the space. I was wondering if
> allocating
> > space on the stack wouldn't be better. That's how arguments that are
> > implicitly pass-by-reference are passed. Also struct return values
> > are forced to lval in stack-allocated memory.
> >
> > Furthermore, malloc would not be possible everywhere (e.g. on GPUs);
> > stack allocation would be supported by more platforms.
>
> I was unable to conceive of a counterpoint to this last argument,
> hence the change.
To make this work for GPUs, we can delegate space allocation to
a gdbarch method, while defining the current malloc-based behavior
as the default hook. Architectures that cannot use malloc can
handle the request their way. If they are not able to make
the allocation, an error may be returned, which is not worse than
the state before your change.
For example, Intel's downstream debugger would be able to allocate
some space in an area in GPU that is specifically reserved for
debugger's use.
Regards
-Baris
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] infcall: Add support for integer literals as reference function paramters
2026-02-02 16:58 ` Keith Seitz
2026-02-02 17:22 ` Aktemur, Tankut Baris
@ 2026-02-12 16:31 ` Tom Tromey
1 sibling, 0 replies; 25+ messages in thread
From: Tom Tromey @ 2026-02-12 16:31 UTC (permalink / raw)
To: Keith Seitz; +Cc: Tom Tromey, gdb-patches
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
>> I'm curious why this change was made.
>> Often I think gdb just coerces to memory via malloc.
Keith> I was persuaded by another reviewer's comments[1]:
Ok. I think it's probably fine really, I was just curious.
Tom
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v5] infcall: Add support for integer literals as reference function parameters
2025-10-16 15:48 [PATCH] infcall: Add support for integer literals as reference function paramters Keith Seitz
` (2 preceding siblings ...)
2026-01-27 19:01 ` [PATCH v4] " Keith Seitz
@ 2026-03-12 14:14 ` Keith Seitz
2026-03-12 16:23 ` Tom de Vries
2026-03-12 17:12 ` [PATCH v6] " Keith Seitz
4 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2026-03-12 14:14 UTC (permalink / raw)
To: gdb-patches
This is v5 of my attempt to add simple integer literal support for refernece
parameters in inferior function calls. The goal here is to take a step toward
a better user experience when working with standard containers such as std::map.
While hacking at the parser to add new related functionality, I've come to realize
that heap allocation is much safer than using the heap. We just really cannot know
how a user (or their program) handles any of these values.
Keith
Changes in v5
- Return to heap allocation
Changes in v4
- Allocate to stack instead of heap
- Use value::force_lval to simply copying to inferior memory
- Add some addition tests
Changes in v3
- Move logic to value_arg_coerce
- Add some attempt to limit copying to trivially copyable types
-----
This patch attempts to mitigate the shortcomings of passing literals
to inferior function calls requiring references. The specific use case here
is std::map's operator[]:
std::map int_map<int, int>;
int_map[1] = 10;
(gdb) print int_map[1]
Attempt to take address of value not located in memory.
This is occurring because while value_coerce_to_target understands
that some values need to be allocated and copied to the inferior's
memory, it only considers the actual parsed type of the argument value,
ignoring the actual type of the function parameter. That is,
Changes in v5
- After reconsideration, return to heap allocation
Changes in v4
- Allocate to stack instead of heap
- Use value::force_lval to simply copying to inferior memory
- Add some addition tests
Changes in v3
- Move logic to value_arg_coerce
- Add some attempt to limit copying to trivially copyable types
in this specific case, the value's parsed type is TYPE_CODE_INT, but
the function requires TYPE_CODE_REF. We need to account for the
reference.
In value_arg_coerce, we have special handling for references, but it
has not specifically dealt with this case. It now checks if the
reference is in memory, and if it isn't, it copies it, if the type
is trivially copyable.
As a result of this patch, the last remaining failure in c++/15372 is now
fixed, and that bug can be closed.
With this patch, we can now print map entries with integer keys:
(gdb) print int_map[1]
$1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
---
gdb/infcall.c | 21 ++-
gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
4 files changed, 256 insertions(+), 7 deletions(-)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 51636ff5403..03fbebf8782 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -246,7 +246,8 @@ show_unwind_on_timeout_p (struct ui_file *file, int from_tty,
static struct value *
value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
- struct type *param_type, int is_prototyped)
+ struct type *param_type, int is_prototyped,
+ CORE_ADDR &sp, struct thread_info *call_thread)
{
const struct builtin_type *builtin = builtin_type (gdbarch);
struct type *arg_type = check_typedef (arg->type ());
@@ -276,10 +277,20 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
- if the value was not previously in memory - in some cases
- we should clearly be allowing this, but how? */
+ convert it back to a reference. If the value is not already
+ in memory (e.g., a literal), we need to allocate space in the
+ inferior and copy it there. */
new_value = value_cast (type->target_type (), arg);
+ if (new_value->lval () != lval_memory
+ && (language_pass_by_reference (new_value->type ())
+ .trivially_copyable))
+ {
+ LONGEST length = check_typedef (new_value->type ())->length ();
+ struct value *addr_val = value_allocate_space_in_inferior (length);
+ CORE_ADDR addr = value_as_address (addr_val);
+ new_value->force_lval (addr);
+ }
+
new_value = value_ref (new_value, type->code ());
return new_value;
}
@@ -1335,7 +1346,7 @@ call_function_by_hand_dummy (struct value *function,
value *original_arg = args[i];
args[i] = value_arg_coerce (gdbarch, args[i],
- param_type, prototyped);
+ param_type, prototyped, sp, call_thread.get ());
if (param_type == NULL)
continue;
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
index 12e2716b435..3c1aa82396a 100644
--- a/gdb/testsuite/gdb.cp/ref-params.cc
+++ b/gdb/testsuite/gdb.cp/ref-params.cc
@@ -60,6 +60,68 @@ int mf2(MultiChild& C)
return mf1(C);
}
+/* A class to be used by functions and methods exercising c++/25957. */
+class TestClass
+{
+ public:
+ int value;
+
+ TestClass (int v) : value (v) {}
+
+ int
+ const_ref_method (const int &x) const
+ {
+ return value + x;
+ }
+
+ int
+ const_ref_method (const TestClass &obj) const
+ {
+ return value + obj.value;
+ }
+
+ int
+ ref_method (int &x)
+ {
+ return value + 2 * x;
+ }
+
+ int
+ ref_method (TestClass &obj)
+ {
+ return value + 2 * obj.value;
+ }
+};
+
+/* Define globals to be used by functions and methods exercising c++/25957. */
+int global_int = 42;
+TestClass global_obj (10);
+
+/* Helper functions to test reference parameter behavior for c++/25957. */
+int
+const_ref_func (const int &x)
+{
+ return x * 2;
+}
+
+int
+const_ref_func (const TestClass &obj)
+{
+ return obj.value * 2;
+}
+
+int
+ref_func (int &x)
+{
+ return x + 1;
+}
+
+int
+ref_func (TestClass &obj)
+{
+ return obj.value + 1;
+}
+
int main(void)
{
Child Q(42);
@@ -76,5 +138,36 @@ int main(void)
mf2(MQ); /* Set breakpoint MQ here. */
- return 0;
+ TestClass obj (5);
+ int local_var = 15;
+
+ /* Prevent compiler from optimizing away the function and method calls. */
+ int dummy_int = 99;
+ (void) const_ref_func (dummy_int);
+ (void) const_ref_func (global_int);
+ (void) const_ref_func (obj);
+ (void) const_ref_func (global_obj);
+ (void) ref_func (dummy_int);
+ (void) ref_func (global_int);
+ (void) ref_func (obj);
+ (void) ref_func (global_obj);
+ (void) obj.const_ref_method (dummy_int);
+ (void) obj.const_ref_method (global_int);
+ (void) obj.const_ref_method (obj);
+ (void) obj.const_ref_method (global_obj);
+ (void) obj.ref_method (dummy_int);
+ (void) obj.ref_method (global_int);
+ (void) obj.ref_method (obj);
+ (void) obj.ref_method (global_obj);
+ (void) global_obj.const_ref_method (dummy_int);
+ (void) global_obj.const_ref_method (global_int);
+ (void) global_obj.const_ref_method (obj);
+ (void) global_obj.const_ref_method (global_obj);
+ (void) global_obj.ref_method (dummy_int);
+ (void) global_obj.ref_method (global_int);
+ (void) global_obj.ref_method (obj);
+ (void) global_obj.ref_method (global_obj);
+
+ /* Breakpoint here for c++/25957 testing. */
+ return 0; /* breakpoint-here */
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
index b61055e9f50..31144fcba21 100644
--- a/gdb/testsuite/gdb.cp/ref-params.exp
+++ b/gdb/testsuite/gdb.cp/ref-params.exp
@@ -63,3 +63,149 @@ gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"
+
+# Inferior function call tests which have reference arguments.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
+gdb_start_again "breakpoint-here"
+
+# Test functions taking const reference parameter.
+gdb_test "print const_ref_func(10)" \
+ "= 20" \
+ "call function with const ref param and literal"
+
+gdb_test "print const_ref_func(global_int)" \
+ "= 84" \
+ "call function with const ref param and global variable"
+
+gdb_test "print const_ref_func(local_var)" \
+ "= 30" \
+ "call function with const ref param and local variable"
+
+gdb_test "print const_ref_func(obj)" \
+ "= 10" \
+ "call function with const ref param and object"
+
+gdb_test "print const_ref_func(global_obj)" \
+ "= 20" \
+ "call function with const ref param and global object"
+
+gdb_test "print const_ref_func((TestClass) {42})" \
+ "= 84" \
+ "call function with const ref param and literal object"
+
+# Test functions taking non-const reference parameter.
+gdb_test "print ref_func(10)" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with non-const ref param and literal"
+
+gdb_test "print ref_func(global_int)" \
+ " = 43" \
+ "call function with non-const ref param and global variable"
+
+gdb_test "print ref_func(local_var)" \
+ " = 16" \
+ "call function with non-const ref param and local variable"
+
+gdb_test "print ref_func(obj)" \
+ "= 6" \
+ "call function with non-const ref param and object"
+
+gdb_test "print ref_func(global_obj)" \
+ "= 11" \
+ "call function with non-const ref param and global object"
+
+gdb_test "print ref_func((TestClass) {42})" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with ref param and literal object"
+
+# Test methods taking constant reference parameter.
+gdb_test "print obj.const_ref_method(5)" \
+ "= 10" \
+ "call const method with const ref param and literal"
+
+gdb_test "print obj.const_ref_method(global_int)" \
+ "= 47" \
+ "call const method with const ref param and global variable"
+
+gdb_test "print obj.const_ref_method(local_var)" \
+ "= 20" \
+ "call const method with const ref param and local variable"
+
+gdb_test "print obj.const_ref_method(obj)" \
+ "= 10" \
+ "call method with const ref param and object"
+
+gdb_test "print obj.const_ref_method((TestClass) {42})" \
+ "= 47" \
+ "call method with const ref param and literal object"
+
+# Test methods taking non-const reference parameters.
+gdb_test "print obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal"
+
+gdb_test "print obj.ref_method(global_int)" \
+ "= 89" \
+ "cal method with non-const ref param and global variable"
+
+gdb_test "print obj.ref_method(local_var)" \
+ " = 35" \
+ "call method with non-const ref param and local variable"
+
+gdb_test "print obj.ref_method(obj)" \
+ "= 15" \
+ "call method with non-const ref param and object"
+
+gdb_test "print obj.ref_method((TestClass) {42})" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal object"
+
+# Test global_obj methods taking constant reference parameter.
+gdb_test "print global_obj.const_ref_method(5)" \
+ "= 15" \
+ "call global const method with const ref param and literal"
+
+gdb_test "print global_obj.const_ref_method(global_int)" \
+ "= 52" \
+ "call global const method with const ref param and global variable"
+
+gdb_test "print global_obj.const_ref_method(local_var)" \
+ "= 25" \
+ "call global const method with const ref param and local variable"
+
+gdb_test "print global_obj.const_ref_method(obj)" \
+ "= 15" \
+ "call global method with const ref param and object"
+
+gdb_test "print global_obj.const_ref_method(global_obj)" \
+ "= 20" \
+ "call global method with const ref param and global object"
+
+gdb_test "print global_obj.const_ref_method((TestClass) {42})" \
+ "= 52" \
+ "call global method with const ref param and literal object"
+
+# Test global_obj methods taking non-const reference parameters.
+gdb_test "print global_obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal"
+
+gdb_test "print global_obj.ref_method(global_int)" \
+ "= 94" \
+ "call global method with non-const ref param and global variable"
+
+gdb_test "print global_obj.ref_method(local_var)" \
+ "= 40" \
+ "call global method with non-const ref param and local variable"
+
+gdb_test "print global_obj.ref_method(obj)" \
+ "= 20" \
+ "call global method with non-const ref param and object"
+
+gdb_test "print global_obj.ref_method(global_obj)" \
+ "= 30" \
+ "call global method with non-const ref param and global object"
+
+gdb_test "print global_obj.ref_method ((TestClass) {42})" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal object"
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index bd6933673db..b9da32c244e 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
gdb_test "print f (ci)" "2" "lvalue reference to const overload"
-setup_kfail "c++/15372" "*-*-*"
gdb_test "print f (3)" "3" "rvalue reference overload"
gdb_test "print g (i)" \
base-commit: 8bdf98b14364adb3f3e90b0a5a08b4a6c8e07fe7
--
2.53.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v5] infcall: Add support for integer literals as reference function parameters
2026-03-12 14:14 ` [PATCH v5] infcall: Add support for integer literals as reference function parameters Keith Seitz
@ 2026-03-12 16:23 ` Tom de Vries
2026-03-12 16:45 ` Keith Seitz
0 siblings, 1 reply; 25+ messages in thread
From: Tom de Vries @ 2026-03-12 16:23 UTC (permalink / raw)
To: Keith Seitz, gdb-patches
On 3/12/26 3:14 PM, Keith Seitz wrote:
> This is v5 of my attempt to add simple integer literal support for refernece
Hi Keith,
refernece -> reference
> parameters in inferior function calls. The goal here is to take a step toward
> a better user experience when working with standard containers such as std::map.
>
> While hacking at the parser to add new related functionality, I've come to realize
> that heap allocation is much safer than using the heap. We just really cannot know
Did you mean: "using the heap"?
FWIW, I've applied the patch and ran the test-case, and confirmed that
it passes.
Also, I applied the test-case from this patch (
https://sourceware.org/pipermail/gdb-patches/2024-November/213340.html )
and confirmed that it also passes with this patch.
I'm not sure if that means that you can claim the corresponding PR as
well, or if it means that the test-case I wrote was not representive of
the PR.
> how a user (or their program) handles any of these values.
>
> Keith
>
> Changes in v5
> - Return to heap allocation
>
> Changes in v4
> - Allocate to stack instead of heap
> - Use value::force_lval to simply copying to inferior memory
> - Add some addition tests
>
> Changes in v3
> - Move logic to value_arg_coerce
> - Add some attempt to limit copying to trivially copyable types
>
> -----
>
> This patch attempts to mitigate the shortcomings of passing literals
> to inferior function calls requiring references. The specific use case here
> is std::map's operator[]:
>
> std::map int_map<int, int>;
> int_map[1] = 10;
> (gdb) print int_map[1]
> Attempt to take address of value not located in memory.
>
> This is occurring because while value_coerce_to_target understands
> that some values need to be allocated and copied to the inferior's
> memory, it only considers the actual parsed type of the argument value,
> ignoring the actual type of the function parameter. That is,
> Changes in v5
> - After reconsideration, return to heap allocation
>
> Changes in v4
> - Allocate to stack instead of heap
> - Use value::force_lval to simply copying to inferior memory
> - Add some addition tests
>
> Changes in v3
> - Move logic to value_arg_coerce
> - Add some attempt to limit copying to trivially copyable types
Is this a pasto? The list seems to be in the middle of some text.
Thanks,
- Tom
> in this specific case, the value's parsed type is TYPE_CODE_INT, but
> the function requires TYPE_CODE_REF. We need to account for the
> reference.
>
> In value_arg_coerce, we have special handling for references, but it
> has not specifically dealt with this case. It now checks if the
> reference is in memory, and if it isn't, it copies it, if the type
> is trivially copyable.
>
> As a result of this patch, the last remaining failure in c++/15372 is now
> fixed, and that bug can be closed.
>
> With this patch, we can now print map entries with integer keys:
>
> (gdb) print int_map[1]
> $1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
> ---
> gdb/infcall.c | 21 ++-
> gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
> gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
> gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
> 4 files changed, 256 insertions(+), 7 deletions(-)
>
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index 51636ff5403..03fbebf8782 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -246,7 +246,8 @@ show_unwind_on_timeout_p (struct ui_file *file, int from_tty,
>
> static struct value *
> value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
> - struct type *param_type, int is_prototyped)
> + struct type *param_type, int is_prototyped,
> + CORE_ADDR &sp, struct thread_info *call_thread)
> {
> const struct builtin_type *builtin = builtin_type (gdbarch);
> struct type *arg_type = check_typedef (arg->type ());
> @@ -276,10 +277,20 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
> - if the value was not previously in memory - in some cases
> - we should clearly be allowing this, but how? */
> + convert it back to a reference. If the value is not already
> + in memory (e.g., a literal), we need to allocate space in the
> + inferior and copy it there. */
> new_value = value_cast (type->target_type (), arg);
> + if (new_value->lval () != lval_memory
> + && (language_pass_by_reference (new_value->type ())
> + .trivially_copyable))
> + {
> + LONGEST length = check_typedef (new_value->type ())->length ();
> + struct value *addr_val = value_allocate_space_in_inferior (length);
> + CORE_ADDR addr = value_as_address (addr_val);
> + new_value->force_lval (addr);
> + }
> +
> new_value = value_ref (new_value, type->code ());
> return new_value;
> }
> @@ -1335,7 +1346,7 @@ call_function_by_hand_dummy (struct value *function,
>
> value *original_arg = args[i];
> args[i] = value_arg_coerce (gdbarch, args[i],
> - param_type, prototyped);
> + param_type, prototyped, sp, call_thread.get ());
>
> if (param_type == NULL)
> continue;
> diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
> index 12e2716b435..3c1aa82396a 100644
> --- a/gdb/testsuite/gdb.cp/ref-params.cc
> +++ b/gdb/testsuite/gdb.cp/ref-params.cc
> @@ -60,6 +60,68 @@ int mf2(MultiChild& C)
> return mf1(C);
> }
>
> +/* A class to be used by functions and methods exercising c++/25957. */
> +class TestClass
> +{
> + public:
> + int value;
> +
> + TestClass (int v) : value (v) {}
> +
> + int
> + const_ref_method (const int &x) const
> + {
> + return value + x;
> + }
> +
> + int
> + const_ref_method (const TestClass &obj) const
> + {
> + return value + obj.value;
> + }
> +
> + int
> + ref_method (int &x)
> + {
> + return value + 2 * x;
> + }
> +
> + int
> + ref_method (TestClass &obj)
> + {
> + return value + 2 * obj.value;
> + }
> +};
> +
> +/* Define globals to be used by functions and methods exercising c++/25957. */
> +int global_int = 42;
> +TestClass global_obj (10);
> +
> +/* Helper functions to test reference parameter behavior for c++/25957. */
> +int
> +const_ref_func (const int &x)
> +{
> + return x * 2;
> +}
> +
> +int
> +const_ref_func (const TestClass &obj)
> +{
> + return obj.value * 2;
> +}
> +
> +int
> +ref_func (int &x)
> +{
> + return x + 1;
> +}
> +
> +int
> +ref_func (TestClass &obj)
> +{
> + return obj.value + 1;
> +}
> +
> int main(void)
> {
> Child Q(42);
> @@ -76,5 +138,36 @@ int main(void)
>
> mf2(MQ); /* Set breakpoint MQ here. */
>
> - return 0;
> + TestClass obj (5);
> + int local_var = 15;
> +
> + /* Prevent compiler from optimizing away the function and method calls. */
> + int dummy_int = 99;
> + (void) const_ref_func (dummy_int);
> + (void) const_ref_func (global_int);
> + (void) const_ref_func (obj);
> + (void) const_ref_func (global_obj);
> + (void) ref_func (dummy_int);
> + (void) ref_func (global_int);
> + (void) ref_func (obj);
> + (void) ref_func (global_obj);
> + (void) obj.const_ref_method (dummy_int);
> + (void) obj.const_ref_method (global_int);
> + (void) obj.const_ref_method (obj);
> + (void) obj.const_ref_method (global_obj);
> + (void) obj.ref_method (dummy_int);
> + (void) obj.ref_method (global_int);
> + (void) obj.ref_method (obj);
> + (void) obj.ref_method (global_obj);
> + (void) global_obj.const_ref_method (dummy_int);
> + (void) global_obj.const_ref_method (global_int);
> + (void) global_obj.const_ref_method (obj);
> + (void) global_obj.const_ref_method (global_obj);
> + (void) global_obj.ref_method (dummy_int);
> + (void) global_obj.ref_method (global_int);
> + (void) global_obj.ref_method (obj);
> + (void) global_obj.ref_method (global_obj);
> +
> + /* Breakpoint here for c++/25957 testing. */
> + return 0; /* breakpoint-here */
> }
> diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
> index b61055e9f50..31144fcba21 100644
> --- a/gdb/testsuite/gdb.cp/ref-params.exp
> +++ b/gdb/testsuite/gdb.cp/ref-params.exp
> @@ -63,3 +63,149 @@ gdb_test "print f1(MQR)" ".* = 53"
> gdb_test "print mf1(MQR)" ".* = 106"
> gdb_test "print mf2(MQR)" ".* = 106"
> gdb_test "print f3(Q.id)" ".* = 42"
> +
> +# Inferior function call tests which have reference arguments.
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
> +gdb_start_again "breakpoint-here"
> +
> +# Test functions taking const reference parameter.
> +gdb_test "print const_ref_func(10)" \
> + "= 20" \
> + "call function with const ref param and literal"
> +
> +gdb_test "print const_ref_func(global_int)" \
> + "= 84" \
> + "call function with const ref param and global variable"
> +
> +gdb_test "print const_ref_func(local_var)" \
> + "= 30" \
> + "call function with const ref param and local variable"
> +
> +gdb_test "print const_ref_func(obj)" \
> + "= 10" \
> + "call function with const ref param and object"
> +
> +gdb_test "print const_ref_func(global_obj)" \
> + "= 20" \
> + "call function with const ref param and global object"
> +
> +gdb_test "print const_ref_func((TestClass) {42})" \
> + "= 84" \
> + "call function with const ref param and literal object"
> +
> +# Test functions taking non-const reference parameter.
> +gdb_test "print ref_func(10)" \
> + "Cannot resolve function ref_func to any overloaded instance" \
> + "call function with non-const ref param and literal"
> +
> +gdb_test "print ref_func(global_int)" \
> + " = 43" \
> + "call function with non-const ref param and global variable"
> +
> +gdb_test "print ref_func(local_var)" \
> + " = 16" \
> + "call function with non-const ref param and local variable"
> +
> +gdb_test "print ref_func(obj)" \
> + "= 6" \
> + "call function with non-const ref param and object"
> +
> +gdb_test "print ref_func(global_obj)" \
> + "= 11" \
> + "call function with non-const ref param and global object"
> +
> +gdb_test "print ref_func((TestClass) {42})" \
> + "Cannot resolve function ref_func to any overloaded instance" \
> + "call function with ref param and literal object"
> +
> +# Test methods taking constant reference parameter.
> +gdb_test "print obj.const_ref_method(5)" \
> + "= 10" \
> + "call const method with const ref param and literal"
> +
> +gdb_test "print obj.const_ref_method(global_int)" \
> + "= 47" \
> + "call const method with const ref param and global variable"
> +
> +gdb_test "print obj.const_ref_method(local_var)" \
> + "= 20" \
> + "call const method with const ref param and local variable"
> +
> +gdb_test "print obj.const_ref_method(obj)" \
> + "= 10" \
> + "call method with const ref param and object"
> +
> +gdb_test "print obj.const_ref_method((TestClass) {42})" \
> + "= 47" \
> + "call method with const ref param and literal object"
> +
> +# Test methods taking non-const reference parameters.
> +gdb_test "print obj.ref_method(5)" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call method with non-const ref param and literal"
> +
> +gdb_test "print obj.ref_method(global_int)" \
> + "= 89" \
> + "cal method with non-const ref param and global variable"
> +
> +gdb_test "print obj.ref_method(local_var)" \
> + " = 35" \
> + "call method with non-const ref param and local variable"
> +
> +gdb_test "print obj.ref_method(obj)" \
> + "= 15" \
> + "call method with non-const ref param and object"
> +
> +gdb_test "print obj.ref_method((TestClass) {42})" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call method with non-const ref param and literal object"
> +
> +# Test global_obj methods taking constant reference parameter.
> +gdb_test "print global_obj.const_ref_method(5)" \
> + "= 15" \
> + "call global const method with const ref param and literal"
> +
> +gdb_test "print global_obj.const_ref_method(global_int)" \
> + "= 52" \
> + "call global const method with const ref param and global variable"
> +
> +gdb_test "print global_obj.const_ref_method(local_var)" \
> + "= 25" \
> + "call global const method with const ref param and local variable"
> +
> +gdb_test "print global_obj.const_ref_method(obj)" \
> + "= 15" \
> + "call global method with const ref param and object"
> +
> +gdb_test "print global_obj.const_ref_method(global_obj)" \
> + "= 20" \
> + "call global method with const ref param and global object"
> +
> +gdb_test "print global_obj.const_ref_method((TestClass) {42})" \
> + "= 52" \
> + "call global method with const ref param and literal object"
> +
> +# Test global_obj methods taking non-const reference parameters.
> +gdb_test "print global_obj.ref_method(5)" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call global method with non-const ref param and literal"
> +
> +gdb_test "print global_obj.ref_method(global_int)" \
> + "= 94" \
> + "call global method with non-const ref param and global variable"
> +
> +gdb_test "print global_obj.ref_method(local_var)" \
> + "= 40" \
> + "call global method with non-const ref param and local variable"
> +
> +gdb_test "print global_obj.ref_method(obj)" \
> + "= 20" \
> + "call global method with non-const ref param and object"
> +
> +gdb_test "print global_obj.ref_method(global_obj)" \
> + "= 30" \
> + "call global method with non-const ref param and global object"
> +
> +gdb_test "print global_obj.ref_method ((TestClass) {42})" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call global method with non-const ref param and literal object"
> diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> index bd6933673db..b9da32c244e 100644
> --- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> +++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> @@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
>
> gdb_test "print f (ci)" "2" "lvalue reference to const overload"
>
> -setup_kfail "c++/15372" "*-*-*"
> gdb_test "print f (3)" "3" "rvalue reference overload"
>
> gdb_test "print g (i)" \
>
> base-commit: 8bdf98b14364adb3f3e90b0a5a08b4a6c8e07fe7
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v5] infcall: Add support for integer literals as reference function parameters
2026-03-12 16:23 ` Tom de Vries
@ 2026-03-12 16:45 ` Keith Seitz
0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2026-03-12 16:45 UTC (permalink / raw)
To: Tom de Vries, gdb-patches
Hi,
On 3/12/26 9:23 AM, Tom de Vries wrote:
> On 3/12/26 3:14 PM, Keith Seitz wrote:
>> This is v5 of my attempt to add simple integer literal support for
>> refernece
>
> Hi Keith,
>
> refernece -> reference
Wowser. I'm blaming a lack of caffeine on all of this.
Please ignore this revision -- I will repost with all the typos fixed.
[And I noticed I forgot to revert some additional changes to
value_arg_coerce...]
> Also, I applied the test-case from this patch ( https://sourceware.org/
> pipermail/gdb-patches/2024-November/213340.html ) and confirmed that it
> also passes with this patch.
>
> I'm not sure if that means that you can claim the corresponding PR as
> well, or if it means that the test-case I wrote was not representive of
> the PR.
I am sorry I completely missed that. We seem to have come to two
different solutions. I will investigate and follow-up in my v6 repost.
>
>> how a user (or their program) handles any of these values.
>>
>> Keith
>>
>> Changes in v5
>> - Return to heap allocation
>>
>> Changes in v4
>> - Allocate to stack instead of heap
>> - Use value::force_lval to simply copying to inferior memory
>> - Add some addition tests
>>
>> Changes in v3
>> - Move logic to value_arg_coerce
>> - Add some attempt to limit copying to trivially copyable types
>>
>> -----
>>
>> This patch attempts to mitigate the shortcomings of passing literals
>> to inferior function calls requiring references. The specific use
>> case here
>> is std::map's operator[]:
>>
>> std::map int_map<int, int>;
>> int_map[1] = 10;
>> (gdb) print int_map[1]
>> Attempt to take address of value not located in memory.
>>
>> This is occurring because while value_coerce_to_target understands
>> that some values need to be allocated and copied to the inferior's
>> memory, it only considers the actual parsed type of the argument value,
>> ignoring the actual type of the function parameter. That is,
>
>> Changes in v5
>> - After reconsideration, return to heap allocation
>>
>> Changes in v4
>> - Allocate to stack instead of heap
>> - Use value::force_lval to simply copying to inferior memory
>> - Add some addition tests
>>
>> Changes in v3
>> - Move logic to value_arg_coerce
>> - Add some attempt to limit copying to trivially copyable types
>
> Is this a pasto? The list seems to be in the middle of some text.
<cough>It certainly is.</cough>
Thank you for taking a look!
Keith
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v6] infcall: Add support for integer literals as reference function parameters
2025-10-16 15:48 [PATCH] infcall: Add support for integer literals as reference function paramters Keith Seitz
` (3 preceding siblings ...)
2026-03-12 14:14 ` [PATCH v5] infcall: Add support for integer literals as reference function parameters Keith Seitz
@ 2026-03-12 17:12 ` Keith Seitz
2026-03-17 14:10 ` Andrew Burgess
4 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2026-03-12 17:12 UTC (permalink / raw)
To: gdb-patches
[With apologies for all the typos in v5...]
This is v6 of my attempt to add simple integer literal support for reference
parameters in inferior function calls. The goal here is to take a step toward
a better user experience when working with standard containers such as std::map.
While hacking at the parser to add new related functionality, I've come to realize
that heap allocation is much safer than using the stack. We just really cannot know
how a user (or their program) handles any of these values.
I've looked at c++/32365, and this patch does not address that issue. I have been
working on a patch to add construction to the parser which will address some of
the issues in that bug, but it relies on this patch. [That is, "p d[var(0)]"
works with my work-in-progress parser patch.]
Keith
Changes in v6
- Fix a bunch of typos
- Revert some missed stack-related changes from v4
Changes in v5
- Return to heap allocation
Changes in v4
- Allocate to stack instead of heap
- Use value::force_lval to simply copying to inferior memory
- Add some addition tests
Changes in v3
- Move logic to value_arg_coerce
- Add some attempt to limit copying to trivially copyable types
-----
This patch attempts to mitigate the shortcomings of passing literals
to inferior function calls requiring references. The specific use case here
is std::map's operator[]:
std::map int_map<int, int>;
int_map[1] = 10;
(gdb) print int_map[1]
Attempt to take address of value not located in memory.
This is occurring because while value_coerce_to_target understands
that some values need to be allocated and copied to the inferior's
memory, it only considers the actual parsed type of the argument value,
ignoring the actual type of the function parameter. That is,
in this specific case, the value's parsed type is TYPE_CODE_INT, but
the function requires TYPE_CODE_REF. We need to account for the
reference.
In value_arg_coerce, we have special handling for references, but it
has not specifically dealt with this case. It now checks if the
reference is in memory, and if it isn't, it copies it, if the type
is trivially copyable.
As a result of this patch, the last remaining failure in c++/15372 is now
fixed, and that bug can be closed.
With this patch, we can now print map entries with integer keys:
(gdb) print int_map[1]
$1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
---
gdb/infcall.c | 16 +-
gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
4 files changed, 253 insertions(+), 5 deletions(-)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 51636ff5403..941b0a95c5b 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -276,10 +276,20 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
- if the value was not previously in memory - in some cases
- we should clearly be allowing this, but how? */
+ convert it back to a reference. If the value is not already
+ in memory (e.g., a literal), we need to allocate space in the
+ inferior and copy it there. */
new_value = value_cast (type->target_type (), arg);
+ if (new_value->lval () != lval_memory
+ && (language_pass_by_reference (new_value->type ())
+ .trivially_copyable))
+ {
+ LONGEST length = check_typedef (new_value->type ())->length ();
+ struct value *addr_val = value_allocate_space_in_inferior (length);
+ CORE_ADDR addr = value_as_address (addr_val);
+ new_value->force_lval (addr);
+ }
+
new_value = value_ref (new_value, type->code ());
return new_value;
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
index 12e2716b435..3c1aa82396a 100644
--- a/gdb/testsuite/gdb.cp/ref-params.cc
+++ b/gdb/testsuite/gdb.cp/ref-params.cc
@@ -60,6 +60,68 @@ int mf2(MultiChild& C)
return mf1(C);
}
+/* A class to be used by functions and methods exercising c++/25957. */
+class TestClass
+{
+ public:
+ int value;
+
+ TestClass (int v) : value (v) {}
+
+ int
+ const_ref_method (const int &x) const
+ {
+ return value + x;
+ }
+
+ int
+ const_ref_method (const TestClass &obj) const
+ {
+ return value + obj.value;
+ }
+
+ int
+ ref_method (int &x)
+ {
+ return value + 2 * x;
+ }
+
+ int
+ ref_method (TestClass &obj)
+ {
+ return value + 2 * obj.value;
+ }
+};
+
+/* Define globals to be used by functions and methods exercising c++/25957. */
+int global_int = 42;
+TestClass global_obj (10);
+
+/* Helper functions to test reference parameter behavior for c++/25957. */
+int
+const_ref_func (const int &x)
+{
+ return x * 2;
+}
+
+int
+const_ref_func (const TestClass &obj)
+{
+ return obj.value * 2;
+}
+
+int
+ref_func (int &x)
+{
+ return x + 1;
+}
+
+int
+ref_func (TestClass &obj)
+{
+ return obj.value + 1;
+}
+
int main(void)
{
Child Q(42);
@@ -76,5 +138,36 @@ int main(void)
mf2(MQ); /* Set breakpoint MQ here. */
- return 0;
+ TestClass obj (5);
+ int local_var = 15;
+
+ /* Prevent compiler from optimizing away the function and method calls. */
+ int dummy_int = 99;
+ (void) const_ref_func (dummy_int);
+ (void) const_ref_func (global_int);
+ (void) const_ref_func (obj);
+ (void) const_ref_func (global_obj);
+ (void) ref_func (dummy_int);
+ (void) ref_func (global_int);
+ (void) ref_func (obj);
+ (void) ref_func (global_obj);
+ (void) obj.const_ref_method (dummy_int);
+ (void) obj.const_ref_method (global_int);
+ (void) obj.const_ref_method (obj);
+ (void) obj.const_ref_method (global_obj);
+ (void) obj.ref_method (dummy_int);
+ (void) obj.ref_method (global_int);
+ (void) obj.ref_method (obj);
+ (void) obj.ref_method (global_obj);
+ (void) global_obj.const_ref_method (dummy_int);
+ (void) global_obj.const_ref_method (global_int);
+ (void) global_obj.const_ref_method (obj);
+ (void) global_obj.const_ref_method (global_obj);
+ (void) global_obj.ref_method (dummy_int);
+ (void) global_obj.ref_method (global_int);
+ (void) global_obj.ref_method (obj);
+ (void) global_obj.ref_method (global_obj);
+
+ /* Breakpoint here for c++/25957 testing. */
+ return 0; /* breakpoint-here */
}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
index b61055e9f50..31144fcba21 100644
--- a/gdb/testsuite/gdb.cp/ref-params.exp
+++ b/gdb/testsuite/gdb.cp/ref-params.exp
@@ -63,3 +63,149 @@ gdb_test "print f1(MQR)" ".* = 53"
gdb_test "print mf1(MQR)" ".* = 106"
gdb_test "print mf2(MQR)" ".* = 106"
gdb_test "print f3(Q.id)" ".* = 42"
+
+# Inferior function call tests which have reference arguments.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
+gdb_start_again "breakpoint-here"
+
+# Test functions taking const reference parameter.
+gdb_test "print const_ref_func(10)" \
+ "= 20" \
+ "call function with const ref param and literal"
+
+gdb_test "print const_ref_func(global_int)" \
+ "= 84" \
+ "call function with const ref param and global variable"
+
+gdb_test "print const_ref_func(local_var)" \
+ "= 30" \
+ "call function with const ref param and local variable"
+
+gdb_test "print const_ref_func(obj)" \
+ "= 10" \
+ "call function with const ref param and object"
+
+gdb_test "print const_ref_func(global_obj)" \
+ "= 20" \
+ "call function with const ref param and global object"
+
+gdb_test "print const_ref_func((TestClass) {42})" \
+ "= 84" \
+ "call function with const ref param and literal object"
+
+# Test functions taking non-const reference parameter.
+gdb_test "print ref_func(10)" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with non-const ref param and literal"
+
+gdb_test "print ref_func(global_int)" \
+ " = 43" \
+ "call function with non-const ref param and global variable"
+
+gdb_test "print ref_func(local_var)" \
+ " = 16" \
+ "call function with non-const ref param and local variable"
+
+gdb_test "print ref_func(obj)" \
+ "= 6" \
+ "call function with non-const ref param and object"
+
+gdb_test "print ref_func(global_obj)" \
+ "= 11" \
+ "call function with non-const ref param and global object"
+
+gdb_test "print ref_func((TestClass) {42})" \
+ "Cannot resolve function ref_func to any overloaded instance" \
+ "call function with ref param and literal object"
+
+# Test methods taking constant reference parameter.
+gdb_test "print obj.const_ref_method(5)" \
+ "= 10" \
+ "call const method with const ref param and literal"
+
+gdb_test "print obj.const_ref_method(global_int)" \
+ "= 47" \
+ "call const method with const ref param and global variable"
+
+gdb_test "print obj.const_ref_method(local_var)" \
+ "= 20" \
+ "call const method with const ref param and local variable"
+
+gdb_test "print obj.const_ref_method(obj)" \
+ "= 10" \
+ "call method with const ref param and object"
+
+gdb_test "print obj.const_ref_method((TestClass) {42})" \
+ "= 47" \
+ "call method with const ref param and literal object"
+
+# Test methods taking non-const reference parameters.
+gdb_test "print obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal"
+
+gdb_test "print obj.ref_method(global_int)" \
+ "= 89" \
+ "cal method with non-const ref param and global variable"
+
+gdb_test "print obj.ref_method(local_var)" \
+ " = 35" \
+ "call method with non-const ref param and local variable"
+
+gdb_test "print obj.ref_method(obj)" \
+ "= 15" \
+ "call method with non-const ref param and object"
+
+gdb_test "print obj.ref_method((TestClass) {42})" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call method with non-const ref param and literal object"
+
+# Test global_obj methods taking constant reference parameter.
+gdb_test "print global_obj.const_ref_method(5)" \
+ "= 15" \
+ "call global const method with const ref param and literal"
+
+gdb_test "print global_obj.const_ref_method(global_int)" \
+ "= 52" \
+ "call global const method with const ref param and global variable"
+
+gdb_test "print global_obj.const_ref_method(local_var)" \
+ "= 25" \
+ "call global const method with const ref param and local variable"
+
+gdb_test "print global_obj.const_ref_method(obj)" \
+ "= 15" \
+ "call global method with const ref param and object"
+
+gdb_test "print global_obj.const_ref_method(global_obj)" \
+ "= 20" \
+ "call global method with const ref param and global object"
+
+gdb_test "print global_obj.const_ref_method((TestClass) {42})" \
+ "= 52" \
+ "call global method with const ref param and literal object"
+
+# Test global_obj methods taking non-const reference parameters.
+gdb_test "print global_obj.ref_method(5)" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal"
+
+gdb_test "print global_obj.ref_method(global_int)" \
+ "= 94" \
+ "call global method with non-const ref param and global variable"
+
+gdb_test "print global_obj.ref_method(local_var)" \
+ "= 40" \
+ "call global method with non-const ref param and local variable"
+
+gdb_test "print global_obj.ref_method(obj)" \
+ "= 20" \
+ "call global method with non-const ref param and object"
+
+gdb_test "print global_obj.ref_method(global_obj)" \
+ "= 30" \
+ "call global method with non-const ref param and global object"
+
+gdb_test "print global_obj.ref_method ((TestClass) {42})" \
+ "Cannot resolve method TestClass::ref_method to any overloaded instance" \
+ "call global method with non-const ref param and literal object"
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index bd6933673db..b9da32c244e 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
gdb_test "print f (ci)" "2" "lvalue reference to const overload"
-setup_kfail "c++/15372" "*-*-*"
gdb_test "print f (3)" "3" "rvalue reference overload"
gdb_test "print g (i)" \
base-commit: 71f898443500ba572511579cf699994828542c96
--
2.53.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6] infcall: Add support for integer literals as reference function parameters
2026-03-12 17:12 ` [PATCH v6] " Keith Seitz
@ 2026-03-17 14:10 ` Andrew Burgess
2026-03-17 18:11 ` Keith Seitz
0 siblings, 1 reply; 25+ messages in thread
From: Andrew Burgess @ 2026-03-17 14:10 UTC (permalink / raw)
To: Keith Seitz, gdb-patches
Keith Seitz <keiths@redhat.com> writes:
> [With apologies for all the typos in v5...]
>
> This is v6 of my attempt to add simple integer literal support for reference
> parameters in inferior function calls. The goal here is to take a step toward
> a better user experience when working with standard containers such as std::map.
>
> While hacking at the parser to add new related functionality, I've come to realize
> that heap allocation is much safer than using the stack. We just really cannot know
> how a user (or their program) handles any of these values.
>
> I've looked at c++/32365, and this patch does not address that issue. I have been
> working on a patch to add construction to the parser which will address some of
> the issues in that bug, but it relies on this patch. [That is, "p d[var(0)]"
> works with my work-in-progress parser patch.]
>
> Keith
>
> Changes in v6
> - Fix a bunch of typos
> - Revert some missed stack-related changes from v4
I took a look through, and this all looks great.
Approved-By: Andrew Burgess <aburgess@redhat.com>
thanks,
Andrew
>
> Changes in v5
> - Return to heap allocation
>
> Changes in v4
> - Allocate to stack instead of heap
> - Use value::force_lval to simply copying to inferior memory
> - Add some addition tests
>
> Changes in v3
> - Move logic to value_arg_coerce
> - Add some attempt to limit copying to trivially copyable types
>
> -----
>
> This patch attempts to mitigate the shortcomings of passing literals
> to inferior function calls requiring references. The specific use case here
> is std::map's operator[]:
>
> std::map int_map<int, int>;
> int_map[1] = 10;
> (gdb) print int_map[1]
> Attempt to take address of value not located in memory.
>
> This is occurring because while value_coerce_to_target understands
> that some values need to be allocated and copied to the inferior's
> memory, it only considers the actual parsed type of the argument value,
> ignoring the actual type of the function parameter. That is,
> in this specific case, the value's parsed type is TYPE_CODE_INT, but
> the function requires TYPE_CODE_REF. We need to account for the
> reference.
>
> In value_arg_coerce, we have special handling for references, but it
> has not specifically dealt with this case. It now checks if the
> reference is in memory, and if it isn't, it copies it, if the type
> is trivially copyable.
>
> As a result of this patch, the last remaining failure in c++/15372 is now
> fixed, and that bug can be closed.
>
> With this patch, we can now print map entries with integer keys:
>
> (gdb) print int_map[1]
> $1 = (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::mapped_type &) @0x41f2d4: 10
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15372
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25957
> ---
> gdb/infcall.c | 16 +-
> gdb/testsuite/gdb.cp/ref-params.cc | 95 +++++++++++-
> gdb/testsuite/gdb.cp/ref-params.exp | 146 +++++++++++++++++++
> gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 1 -
> 4 files changed, 253 insertions(+), 5 deletions(-)
>
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index 51636ff5403..941b0a95c5b 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -276,10 +276,20 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *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
> - if the value was not previously in memory - in some cases
> - we should clearly be allowing this, but how? */
> + convert it back to a reference. If the value is not already
> + in memory (e.g., a literal), we need to allocate space in the
> + inferior and copy it there. */
> new_value = value_cast (type->target_type (), arg);
> + if (new_value->lval () != lval_memory
> + && (language_pass_by_reference (new_value->type ())
> + .trivially_copyable))
> + {
> + LONGEST length = check_typedef (new_value->type ())->length ();
> + struct value *addr_val = value_allocate_space_in_inferior (length);
> + CORE_ADDR addr = value_as_address (addr_val);
> + new_value->force_lval (addr);
> + }
> +
> new_value = value_ref (new_value, type->code ());
> return new_value;
> }
> diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
> index 12e2716b435..3c1aa82396a 100644
> --- a/gdb/testsuite/gdb.cp/ref-params.cc
> +++ b/gdb/testsuite/gdb.cp/ref-params.cc
> @@ -60,6 +60,68 @@ int mf2(MultiChild& C)
> return mf1(C);
> }
>
> +/* A class to be used by functions and methods exercising c++/25957. */
> +class TestClass
> +{
> + public:
> + int value;
> +
> + TestClass (int v) : value (v) {}
> +
> + int
> + const_ref_method (const int &x) const
> + {
> + return value + x;
> + }
> +
> + int
> + const_ref_method (const TestClass &obj) const
> + {
> + return value + obj.value;
> + }
> +
> + int
> + ref_method (int &x)
> + {
> + return value + 2 * x;
> + }
> +
> + int
> + ref_method (TestClass &obj)
> + {
> + return value + 2 * obj.value;
> + }
> +};
> +
> +/* Define globals to be used by functions and methods exercising c++/25957. */
> +int global_int = 42;
> +TestClass global_obj (10);
> +
> +/* Helper functions to test reference parameter behavior for c++/25957. */
> +int
> +const_ref_func (const int &x)
> +{
> + return x * 2;
> +}
> +
> +int
> +const_ref_func (const TestClass &obj)
> +{
> + return obj.value * 2;
> +}
> +
> +int
> +ref_func (int &x)
> +{
> + return x + 1;
> +}
> +
> +int
> +ref_func (TestClass &obj)
> +{
> + return obj.value + 1;
> +}
> +
> int main(void)
> {
> Child Q(42);
> @@ -76,5 +138,36 @@ int main(void)
>
> mf2(MQ); /* Set breakpoint MQ here. */
>
> - return 0;
> + TestClass obj (5);
> + int local_var = 15;
> +
> + /* Prevent compiler from optimizing away the function and method calls. */
> + int dummy_int = 99;
> + (void) const_ref_func (dummy_int);
> + (void) const_ref_func (global_int);
> + (void) const_ref_func (obj);
> + (void) const_ref_func (global_obj);
> + (void) ref_func (dummy_int);
> + (void) ref_func (global_int);
> + (void) ref_func (obj);
> + (void) ref_func (global_obj);
> + (void) obj.const_ref_method (dummy_int);
> + (void) obj.const_ref_method (global_int);
> + (void) obj.const_ref_method (obj);
> + (void) obj.const_ref_method (global_obj);
> + (void) obj.ref_method (dummy_int);
> + (void) obj.ref_method (global_int);
> + (void) obj.ref_method (obj);
> + (void) obj.ref_method (global_obj);
> + (void) global_obj.const_ref_method (dummy_int);
> + (void) global_obj.const_ref_method (global_int);
> + (void) global_obj.const_ref_method (obj);
> + (void) global_obj.const_ref_method (global_obj);
> + (void) global_obj.ref_method (dummy_int);
> + (void) global_obj.ref_method (global_int);
> + (void) global_obj.ref_method (obj);
> + (void) global_obj.ref_method (global_obj);
> +
> + /* Breakpoint here for c++/25957 testing. */
> + return 0; /* breakpoint-here */
> }
> diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
> index b61055e9f50..31144fcba21 100644
> --- a/gdb/testsuite/gdb.cp/ref-params.exp
> +++ b/gdb/testsuite/gdb.cp/ref-params.exp
> @@ -63,3 +63,149 @@ gdb_test "print f1(MQR)" ".* = 53"
> gdb_test "print mf1(MQR)" ".* = 106"
> gdb_test "print mf2(MQR)" ".* = 106"
> gdb_test "print f3(Q.id)" ".* = 42"
> +
> +# Inferior function call tests which have reference arguments.
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=25957
> +gdb_start_again "breakpoint-here"
> +
> +# Test functions taking const reference parameter.
> +gdb_test "print const_ref_func(10)" \
> + "= 20" \
> + "call function with const ref param and literal"
> +
> +gdb_test "print const_ref_func(global_int)" \
> + "= 84" \
> + "call function with const ref param and global variable"
> +
> +gdb_test "print const_ref_func(local_var)" \
> + "= 30" \
> + "call function with const ref param and local variable"
> +
> +gdb_test "print const_ref_func(obj)" \
> + "= 10" \
> + "call function with const ref param and object"
> +
> +gdb_test "print const_ref_func(global_obj)" \
> + "= 20" \
> + "call function with const ref param and global object"
> +
> +gdb_test "print const_ref_func((TestClass) {42})" \
> + "= 84" \
> + "call function with const ref param and literal object"
> +
> +# Test functions taking non-const reference parameter.
> +gdb_test "print ref_func(10)" \
> + "Cannot resolve function ref_func to any overloaded instance" \
> + "call function with non-const ref param and literal"
> +
> +gdb_test "print ref_func(global_int)" \
> + " = 43" \
> + "call function with non-const ref param and global variable"
> +
> +gdb_test "print ref_func(local_var)" \
> + " = 16" \
> + "call function with non-const ref param and local variable"
> +
> +gdb_test "print ref_func(obj)" \
> + "= 6" \
> + "call function with non-const ref param and object"
> +
> +gdb_test "print ref_func(global_obj)" \
> + "= 11" \
> + "call function with non-const ref param and global object"
> +
> +gdb_test "print ref_func((TestClass) {42})" \
> + "Cannot resolve function ref_func to any overloaded instance" \
> + "call function with ref param and literal object"
> +
> +# Test methods taking constant reference parameter.
> +gdb_test "print obj.const_ref_method(5)" \
> + "= 10" \
> + "call const method with const ref param and literal"
> +
> +gdb_test "print obj.const_ref_method(global_int)" \
> + "= 47" \
> + "call const method with const ref param and global variable"
> +
> +gdb_test "print obj.const_ref_method(local_var)" \
> + "= 20" \
> + "call const method with const ref param and local variable"
> +
> +gdb_test "print obj.const_ref_method(obj)" \
> + "= 10" \
> + "call method with const ref param and object"
> +
> +gdb_test "print obj.const_ref_method((TestClass) {42})" \
> + "= 47" \
> + "call method with const ref param and literal object"
> +
> +# Test methods taking non-const reference parameters.
> +gdb_test "print obj.ref_method(5)" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call method with non-const ref param and literal"
> +
> +gdb_test "print obj.ref_method(global_int)" \
> + "= 89" \
> + "cal method with non-const ref param and global variable"
> +
> +gdb_test "print obj.ref_method(local_var)" \
> + " = 35" \
> + "call method with non-const ref param and local variable"
> +
> +gdb_test "print obj.ref_method(obj)" \
> + "= 15" \
> + "call method with non-const ref param and object"
> +
> +gdb_test "print obj.ref_method((TestClass) {42})" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call method with non-const ref param and literal object"
> +
> +# Test global_obj methods taking constant reference parameter.
> +gdb_test "print global_obj.const_ref_method(5)" \
> + "= 15" \
> + "call global const method with const ref param and literal"
> +
> +gdb_test "print global_obj.const_ref_method(global_int)" \
> + "= 52" \
> + "call global const method with const ref param and global variable"
> +
> +gdb_test "print global_obj.const_ref_method(local_var)" \
> + "= 25" \
> + "call global const method with const ref param and local variable"
> +
> +gdb_test "print global_obj.const_ref_method(obj)" \
> + "= 15" \
> + "call global method with const ref param and object"
> +
> +gdb_test "print global_obj.const_ref_method(global_obj)" \
> + "= 20" \
> + "call global method with const ref param and global object"
> +
> +gdb_test "print global_obj.const_ref_method((TestClass) {42})" \
> + "= 52" \
> + "call global method with const ref param and literal object"
> +
> +# Test global_obj methods taking non-const reference parameters.
> +gdb_test "print global_obj.ref_method(5)" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call global method with non-const ref param and literal"
> +
> +gdb_test "print global_obj.ref_method(global_int)" \
> + "= 94" \
> + "call global method with non-const ref param and global variable"
> +
> +gdb_test "print global_obj.ref_method(local_var)" \
> + "= 40" \
> + "call global method with non-const ref param and local variable"
> +
> +gdb_test "print global_obj.ref_method(obj)" \
> + "= 20" \
> + "call global method with non-const ref param and object"
> +
> +gdb_test "print global_obj.ref_method(global_obj)" \
> + "= 30" \
> + "call global method with non-const ref param and global object"
> +
> +gdb_test "print global_obj.ref_method ((TestClass) {42})" \
> + "Cannot resolve method TestClass::ref_method to any overloaded instance" \
> + "call global method with non-const ref param and literal object"
> diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> index bd6933673db..b9da32c244e 100644
> --- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> +++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> @@ -64,7 +64,6 @@ gdb_test "print f (i)" "1" "lvalue reference overload"
>
> gdb_test "print f (ci)" "2" "lvalue reference to const overload"
>
> -setup_kfail "c++/15372" "*-*-*"
> gdb_test "print f (3)" "3" "rvalue reference overload"
>
> gdb_test "print g (i)" \
>
> base-commit: 71f898443500ba572511579cf699994828542c96
> --
> 2.53.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6] infcall: Add support for integer literals as reference function parameters
2026-03-17 14:10 ` Andrew Burgess
@ 2026-03-17 18:11 ` Keith Seitz
0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2026-03-17 18:11 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches
On 3/17/26 7:10 AM, Andrew Burgess wrote:
> Keith Seitz <keiths@redhat.com> writes:
>> Changes in v6
>> - Fix a bunch of typos
>> - Revert some missed stack-related changes from v4
>
> I took a look through, and this all looks great.
>
> Approved-By: Andrew Burgess <aburgess@redhat.com>
Thank you for the quick review! I've pushed this patch.
Keith
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2026-03-17 18:12 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-16 15:48 [PATCH] infcall: Add support for integer literals as reference function paramters Keith Seitz
2025-10-17 14:49 ` Tom Tromey
2025-10-20 19:00 ` Keith Seitz
2025-10-20 19:36 ` [PATCH v2] " Keith Seitz
2025-10-21 20:19 ` Tom Tromey
2025-10-22 12:05 ` Andrew Burgess
2025-10-22 13:21 ` Tom Tromey
2026-01-22 19:05 ` Keith Seitz
2026-01-23 14:07 ` Aktemur, Tankut Baris
2026-01-27 18:43 ` Keith Seitz
2026-01-27 19:01 ` [PATCH v4] " Keith Seitz
2026-01-28 8:24 ` Aktemur, Tankut Baris
2026-01-28 13:54 ` Andrew Burgess
2026-02-02 17:05 ` Aktemur, Tankut Baris
2026-02-02 17:21 ` Keith Seitz
2026-01-30 20:59 ` Tom Tromey
2026-02-02 16:58 ` Keith Seitz
2026-02-02 17:22 ` Aktemur, Tankut Baris
2026-02-12 16:31 ` Tom Tromey
2026-03-12 14:14 ` [PATCH v5] infcall: Add support for integer literals as reference function parameters Keith Seitz
2026-03-12 16:23 ` Tom de Vries
2026-03-12 16:45 ` Keith Seitz
2026-03-12 17:12 ` [PATCH v6] " Keith Seitz
2026-03-17 14:10 ` Andrew Burgess
2026-03-17 18:11 ` Keith Seitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox