public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Hannes Domani <ssbssa@yahoo.de>
To: gdb-patches@sourceware.org
Subject: [PATCH v2] Allow calling of variadic C++ functions
Date: Wed, 13 Dec 2023 19:11:09 +0100	[thread overview]
Message-ID: <20231213181109.3572-1-ssbssa@yahoo.de> (raw)
In-Reply-To: <20231213181109.3572-1-ssbssa.ref@yahoo.de>

Currently, it's not possible to call a variadic C++ function:
```
(gdb) print sum_vararg_int(1, 10)
Cannot resolve function sum_vararg_int to any overloaded instance
(gdb) print sum_vararg_int(2, 20, 30)
Cannot resolve function sum_vararg_int to any overloaded instance
```

It's because all additional arguments get the TOO_FEW_PARAMS_BADNESS
rank by rank_function, which disqualifies the function.

To fix this, I've created the new VARARG_BADNESS rank, which is
used only for additional arguments of variadic functions, allowing
them to be called:
```
(gdb) print sum_vararg_int(1, 10)
$1 = 10
(gdb) print sum_vararg_int(2, 20, 30)
$2 = 50
```

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28589
---
v2:
- Fixed ranking of overloaded varargs functions, plus some tests
  added for this.
---
 gdb/gdbtypes.c                  |  9 ++++++---
 gdb/gdbtypes.h                  |  3 ++-
 gdb/testsuite/gdb.cp/call-c.cc  | 26 ++++++++++++++++++++++++++
 gdb/testsuite/gdb.cp/call-c.exp | 13 +++++++++++++
 gdb/valops.c                    | 10 ++++++++--
 5 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 4c70c9b8ae6..2580b4f19ee 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -76,6 +76,7 @@ const struct rank REFERENCE_SEE_THROUGH_BADNESS = {0,1};
 const struct rank NULL_POINTER_CONVERSION_BADNESS = {2,0};
 const struct rank NS_POINTER_CONVERSION_BADNESS = {10,0};
 const struct rank NS_INTEGER_POINTER_CONVERSION_BADNESS = {3,0};
+const struct rank VARARG_BADNESS = {4, 0};
 
 /* Floatformat pairs.  */
 const struct floatformat *floatformats_ieee_half[BFD_ENDIAN_UNKNOWN] = {
@@ -4038,7 +4039,8 @@ compare_badness (const badness_vector &a, const badness_vector &b)
 
 badness_vector
 rank_function (gdb::array_view<type *> parms,
-	       gdb::array_view<value *> args)
+	       gdb::array_view<value *> args,
+	       bool varargs)
 {
   /* add 1 for the length-match rank.  */
   badness_vector bv;
@@ -4051,7 +4053,8 @@ rank_function (gdb::array_view<type *> parms,
      arguments and ellipsis parameter lists, we should consider those
      and rank the length-match more finely.  */
 
-  bv.push_back ((args.size () != parms.size ())
+  bv.push_back ((args.size () != parms.size ()
+		 && (! varargs || args.size () < parms.size ()))
 		? LENGTH_MISMATCH_BADNESS
 		: EXACT_MATCH_BADNESS);
 
@@ -4064,7 +4067,7 @@ rank_function (gdb::array_view<type *> parms,
 
   /* If more arguments than parameters, add dummy entries.  */
   for (size_t i = min_len; i < args.size (); i++)
-    bv.push_back (TOO_FEW_PARAMS_BADNESS);
+    bv.push_back (varargs ? VARARG_BADNESS : TOO_FEW_PARAMS_BADNESS);
 
   return bv;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index eca92196364..4b563e79546 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -2735,7 +2735,8 @@ extern int compare_badness (const badness_vector &,
 			    const badness_vector &);
 
 extern badness_vector rank_function (gdb::array_view<type *> parms,
-				     gdb::array_view<value *> args);
+				     gdb::array_view<value *> args,
+				     bool varargs = false);
 
 extern struct rank rank_one_type (struct type *, struct type *,
 				  struct value *);
diff --git a/gdb/testsuite/gdb.cp/call-c.cc b/gdb/testsuite/gdb.cp/call-c.cc
index 4362bbf2143..1677755b4b9 100644
--- a/gdb/testsuite/gdb.cp/call-c.cc
+++ b/gdb/testsuite/gdb.cp/call-c.cc
@@ -15,6 +15,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#include <stdarg.h>
+
 int func(int x)
 {
    return x;
@@ -33,6 +35,29 @@ extern "C" {
   int foo(int);
 }
 
+int sum_vararg_int (int count, ...)
+{
+  va_list va;
+  int sum = 0;
+
+  va_start (va, count);
+  for (int i = 0; i < count; i++)
+    sum += va_arg (va, int);
+  va_end (va);
+
+  return sum;
+}
+
+int vararg_func (int a, ...)
+{
+  return 1;
+}
+
+int vararg_func (int a, int b, ...)
+{
+  return 2;
+}
+
 int main()
 {
     Foo f;
@@ -41,5 +66,6 @@ int main()
     FooHandle handle = pf;
     rf->func(); /* set breakpoint here */
     foo(0);
+    sum_vararg_int (1, 5);
     return func(0);
 }
diff --git a/gdb/testsuite/gdb.cp/call-c.exp b/gdb/testsuite/gdb.cp/call-c.exp
index b20bc8698ca..36c0c1e2a75 100644
--- a/gdb/testsuite/gdb.cp/call-c.exp
+++ b/gdb/testsuite/gdb.cp/call-c.exp
@@ -38,5 +38,18 @@ gdb_test "print foo(1)" "\\\$$decimal = 1"
 gdb_test "continue" ".*breakpoint here.*" "continue to bp"
 gdb_test "print rf->func()" "\\\$$decimal = 1"
 
+gdb_test "print sum_vararg_int(0)" "0"
+gdb_test "print sum_vararg_int(1, 10)" "10"
+gdb_test "print sum_vararg_int(2, 20, 30)" "50"
+gdb_test "print sum_vararg_int(5, 20, 30, 40, 50, 60)" "200"
+
+gdb_test "print vararg_func(1)" "1"
+gdb_test "print vararg_func(2, 3)" "2"
+gdb_test "print vararg_func(4, 5.5)" "2"
+gdb_test "print vararg_func(6, \"7\")" "1"
+gdb_test "print vararg_func(8, 9, 10)" "2"
+gdb_test "print vararg_func(11, 12, 13.5)" "2"
+gdb_test "print vararg_func(14, 15, \"16\")" "2"
+
 # Regression test for method call via a typedef.
 gdb_test "print handle->func()" "\\\$$decimal = 1"
diff --git a/gdb/valops.c b/gdb/valops.c
index 49ea1fd7676..a15c92bd222 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -3226,6 +3226,7 @@ find_oload_champ (gdb::array_view<value *> args,
     {
       int jj;
       int static_offset = 0;
+      bool varargs = false;
       std::vector<type *> parm_types;
 
       if (xmethods != NULL)
@@ -3238,9 +3239,13 @@ find_oload_champ (gdb::array_view<value *> args,
 	    {
 	      nparms = TYPE_FN_FIELD_TYPE (methods, ix)->num_fields ();
 	      static_offset = oload_method_static_p (methods, ix);
+	      varargs = TYPE_FN_FIELD_TYPE (methods, ix)->has_varargs ();
 	    }
 	  else
-	    nparms = functions[ix]->type ()->num_fields ();
+	    {
+	      nparms = functions[ix]->type ()->num_fields ();
+	      varargs = functions[ix]->type ()->has_varargs ();
+	    }
 
 	  parm_types.reserve (nparms);
 	  for (jj = 0; jj < nparms; jj++)
@@ -3255,7 +3260,8 @@ find_oload_champ (gdb::array_view<value *> args,
       /* Compare parameter types to supplied argument types.  Skip
 	 THIS for static methods.  */
       bv = rank_function (parm_types,
-			  args.slice (static_offset));
+			  args.slice (static_offset),
+			  varargs);
 
       if (overload_debug)
 	{
-- 
2.35.1


       reply	other threads:[~2023-12-13 18:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20231213181109.3572-1-ssbssa.ref@yahoo.de>
2023-12-13 18:11 ` Hannes Domani [this message]
2023-12-13 20:09   ` Tom Tromey
2023-12-14 15:20     ` Hannes Domani

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231213181109.3572-1-ssbssa@yahoo.de \
    --to=ssbssa@yahoo.de \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).