]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
infcall: Add support for integer literals as reference function parameters
authorKeith Seitz <keiths@redhat.com>
Thu, 16 Oct 2025 15:29:05 +0000 (08:29 -0700)
committerKeith Seitz <keiths@redhat.com>
Tue, 17 Mar 2026 17:02:51 +0000 (10:02 -0700)
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
Approved-By: Andrew Burgess <aburgess@redhat.com>
gdb/infcall.c
gdb/testsuite/gdb.cp/ref-params.cc
gdb/testsuite/gdb.cp/ref-params.exp
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp

index 51636ff5403115f84e4809228947e00f54180ab4..941b0a95c5b7e88f3e73324a28d78666bad6a732 100644 (file)
@@ -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;
       }
index 12e2716b4354d9ae1838eea438b5ac5517133a4e..3c1aa82396a148d43971f933292fc8cc48a0605a 100644 (file)
@@ -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 */
 }
index b61055e9f5057d632388c0c28c0a70ad729c014a..31144fcba213eac01bf93e16d40753aedef875c6 100644 (file)
@@ -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"
index bd6933673dbc0cc92d6b75f42ada2bafcabe94af..b9da32c244e431115b70e9e077c7d51a6da423b2 100644 (file)
@@ -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)" \